There are two versions of this script, the first is for running each simulation to the end and then saving the final step as the output of the model and the second is to save outputs along the way so we can evaluate how different models change through time.

Here is the first, and primary, version:



#####################################################################

# Run the full model in a cluster. This version writes files to a cluster output folder.
# rm(list = ls())
# install.packages("~/Desktop/FARM_1.0.tar.gz", repos=NULL, type="source")


#####################################################################
## need to document which functions we use from each of these libraries. 
library(ape)
library(spdep)
library(Rcpp)
library(msm)
library(FARM)


sim_run_cluster <- function(replicate_cycle, myWorld, number_of_time_steps, nbs,
                            number_of_tips, number_of_neighbors, origins, start = NULL) {
  # Calls the full simulation script 
  #  
  # Purpose: Need to wrap the entire simulation script into a function so it can be called in parallel from a cluster call  
  #
  # Args:
  #    replicate_cycle: An integer indicating the replicate number of a simulation. This variable is used in this function to label        
  #         the saved output file and control the number of replicates run by the cluster.
  #
  #    combo_number: An interger between 1 and 31 indicating the combinations of S, E, A, D, and T modules to be included 
  #         in the simulation. The full list of these combinations can be printed using the function combo_of_choice(28, TRUE).
  #         We are currently using combinations 25,28,29,and 31 as our four competing models for the spread of agriculture.  
  #
  #    myWorld: Matrix that defines the scope of the available world and acts as a data hub for organizing and reporting      
  #         results from the different elements of the simulation. 
  #
  #    number_of_time_steps: An integer indicating how many iterations the simulation will calculated before writing the data 
  #         file. 
  #
  #    nbs: A list of the available neighbors for each spatial point. This is passed to the function for calculating the interaction 
  #         of neighbors through time. 
  #
  #    number_of_tips: An interger indicating the number of tree tips the simulation should be truncated to. The default is to 
  #         include all the available tips (e.g. 1254 for human languages). 
  #
  # Returns: 
  #    myOut: A list object containing a 'phylo' tree object called mytree in the first position and the myWorld matrix of 
  #         spatial and tree data in the second position 
  #     
  

  x1 <- 4 #Number of runs per core
  sampleer <- sample(c(1,2,5,6), x1)
  #if (replicate_cycle != 1) {
  #  replicate_cycle <- ((replicate_cycle - 1) * x1) + 1
 # }
 # replicate_cycle <- replicate_cycle:(replicate_cycle + (x1 - 1))
  for (count in sampleer) {
  independent <- 1 

    
    # Probability of Arisal
    prob_choose_a <- rev(sort(rexp(4, rate = 9)))
    prob_choose_a <- prob_choose_a[c(sample(1:2, 2), sample(3:4, 2))]
    prob_choose_a[3] <- 0
    P.Arisal0  <- parameters(prob_choose_a[1], prob_choose_a[4],
                             prob_choose_a[3], prob_choose_a[2],
                             "Env_NonD", "Env_D",
                             "Evol_to_F", "Evol_to_D")
    # P.Arisal0 is the one you should change the parameters
    P.Arisal <- matrix(NA, ncol = 2, nrow = nrow(myWorld)) # probability per cell
    colnames(P.Arisal) <- c("Evolve_to_F", "Evolve_to_D")
    Env.Dom <- myWorld[, 7] == 2
    P.Arisal[Env.Dom, 1] <- P.Arisal0[1, 2]
    P.Arisal[!Env.Dom, 1] <- P.Arisal0[1, 1]
    P.Arisal[Env.Dom, 2] <- P.Arisal0[2, 2]
    P.Arisal[!Env.Dom, 2] <- P.Arisal0[2, 1]
    
    colnames(P.Arisal) <- c("Prob_of_Foraging", "Prob_of_Domestication")
    P.Arisal[which(origins == FALSE), 2]  <- 0
    
    #####
    #prob_choose <- runif(12, 0.01, 1)
    #sub <- (prob_choose[1] - 0.01)
    #sub <- ifelse(sub < .1, .1, sub)
    #prob_choose[c(4)] <- runif(1, 0.01, sub)
    #prob_choose[c(5)] <- runif(1, 0.1, 1) # High extinction
    #prob_choose[c(6)] <- runif(1, 0, (prob_choose[3] - 0.01))
    #prob_choose[c(9, 10, 12)] <- runif(3, 0.01, prob_choose[11])
    
    ####
    prob_choose <- runif(12, 0, 1)
    top <- min(prob_choose[c(1,3)], na.rm=TRUE)
    prob_choose[c(2)] <- runif(1, 0, top)
    
    prob_choose[c(5)] <- runif(1, 0, prob_choose[c(2)]) 
    prob_choose[c(6)] <- runif(1, 0, prob_choose[c(5)])
    prob_choose[c(4)] <- runif(1, prob_choose[c(6)], prob_choose[c(5)])
    
        
    if (count == 1) {
      prob_choose[7:12] <- 0
    }
    if (count == 2) {
      prob_choose[9:12] <- 0
    }
    if (count == 3 | count == 5) {
      prob_choose[7:8] <- 0
      independent <- 0
    }
    if (count == 4 | count == 6) {
      independent <- 0
    }
    
    
    P.speciation <- parameters(prob_choose[1], prob_choose[1],
                               prob_choose[2], prob_choose[3],
                               "Env_NonD", "Env_D", "For", "Dom")

    P.extinction  <- parameters(prob_choose[4], prob_choose[4],
                                prob_choose[5], prob_choose[6],
                                "Env_NonD", "Env_D", "For", "Dom")

    
    P.diffusion <- parameters(0, prob_choose[7],
                              prob_choose[8], 0,
                              "Target_For", "Target_Dom",
                              "Source_For", "Source_Dom")
    
    P.TakeOver <- parameters(prob_choose[9], prob_choose[10],
                             prob_choose[11], prob_choose[12],
                             "Target_For", "Target_Dom",
                             "Source_For", "Source_Dom")
    multiplier <- 1 # always 1 now.
   if (count %in% 1:4) { 
        myOut <- RunSimUltimate(myWorld, P.extinction, P.speciation, 
                            P.diffusion, P.Arisal, P.TakeOver, nbs, independent,
                            N.steps = number_of_time_steps, silent = FALSE, 
                            multiplier = multiplier, start = start)
                            }
   if (count %in% 5:6) {
        myOut <- RunSimUltimate.push(myWorld, P.extinction, P.speciation, 
                            P.diffusion, P.Arisal, P.TakeOver, nbs, independent,
                            N.steps = number_of_time_steps, silent = FALSE, 
                            multiplier = multiplier, start = start)
                            }
                            
                            
    # Count refers to the combo, 1 = null, 2 = diffusion, 3 = Takeover, 4 = full
    save(myOut,  file= paste0("./Module_1_outputs/myOut_rep_",
                              formatC(replicate_cycle, width = 2,flag = 0),
                              "_combo_",
                              formatC(count, width = 2,flag = 0),
                              "_","params", "_P.speciation_",
                              paste(formatC(P.speciation, width = 2,flag = 0), collapse="_"),"_P.extinct_",
                              paste(formatC(P.extinction, width = 2,flag = 0), collapse="_"), "_P.diffus_",
                              paste(formatC(P.diffusion, width = 2,flag = 0), collapse="_"), "_P.TO_",
                              paste(formatC(P.TakeOver, width = 2,flag = 0), collapse="_"),"_P.Arisal_",
                              paste(formatC(P.Arisal0, width = 2,flag = 0), collapse="_"),
                              "_timesteps_", number_of_time_steps, "_NBS_", number_of_neighbors, "_.Rdata"))

    Sim_statistics <- Module_2(myOut)

    save(Sim_statistics, file= paste0("./Module_2_outputs/Sim_stats_rep_",
                                      formatC(replicate_cycle, width = 2,flag = 0),
                                      "_combo_",
                                      formatC(count, width = 2,flag = 0),
                                      "_","params", "_P.speciation_",
                                      paste(formatC(P.speciation, width = 2,flag = 0), collapse="_"),"_P.extinct_",
                                      paste(formatC(P.extinction, width = 2,flag = 0), collapse="_"), "_P.diffus_",
                                      paste(formatC(P.diffusion, width = 2,flag = 0), collapse="_"), "_P.TO_",
                                      paste(formatC(P.TakeOver, width = 2,flag = 0), collapse="_"),"_P.Arisal_",
                                      paste(formatC(P.Arisal0, width = 2,flag = 0), collapse="_"),
                                      "_timesteps_", number_of_time_steps, "_NBS_", number_of_neighbors, "_.Rdata"))
  }
  
}

#####################################################################
coords <- as.matrix(apply(language_centroids[, 3:4], 2, as.numeric)) #coords
conds <- ifelse(suitability2 == 0, 1, 2)
conds[is.na(conds)] <- sample(c(1, 2), sum(is.na(conds)), replace = TRUE) 
origins <- language_centroids[, 5]

##### Specify simulation parameters #################################

number_of_tips <- length(coords[,1])
number_of_time_steps_a <- 30000
#replicate_cycle <- c(1)  #number of replicates
#####################################################################
data("parameters.table")


system.time(
  myWorld <- BuildWorld(coords, conds)
)
number_of_neighbors <- sample(5:9,1)

nbs <- knn2nb(knearneigh(coords, k = number_of_neighbors, longlat = TRUE),
              sym = TRUE) # 7 symmetric neighbors
n.obs <- sapply(nbs, length)
seq.max <- seq_len(max(n.obs))
nbs <- t(sapply(nbs, "[", i = seq.max))

dim(myWorld)


# NAI <- 1000
args <- commandArgs(trailingOnly = FALSE)
print(args)
NAI <- as.numeric(args[7])
#setwd("~/Box Sync/colliding ranges/Simulations_humans/big world cluster outputs")


# Starting point
start <- sample((1:nrow(language_centroids))[as.logical(language_centroids[, 6])], 1)

#sim_run_cluster(replicate_cycle = NAI,
#                myWorld, number_of_time_steps = number_of_time_steps_a, 
#                nbs, number_of_tips = nrow(myWorld), number_of_neighbors= number_of_neighbors, #origins=origins,start = start)

Here is the second version



#####################################################################

# Run the full model in a cluster. This version writes files to a cluster output folder.
# rm(list = ls())
# install.packages("~/Desktop/FARM_1.0.tar.gz", repos=NULL, type="source")


#####################################################################
## need to document which functions we use from each of these libraries. 
library(ape)
library(spdep)
library(Rcpp)
library(msm)
library(FARM)


sim_run_cluster <- function(replicate_cycle, myWorld, number_of_time_steps, nbs,
                            number_of_tips, number_of_neighbors, origins, start = NULL) {
  # Calls the full simulation script 
  #  
  # Purpose: Need to wrap the entire simulation script into a function so it can be called in parallel from a cluster call  
  #
  # Args:
  #    replicate_cycle: An integer indicating the replicate number of a simulation. This variable is used in this function to label        
  #         the saved output file and control the number of replicates run by the cluster.
  #
  #    combo_number: An interger between 1 and 31 indicating the combinations of S, E, A, D, and T modules to be included 
  #         in the simulation. The full list of these combinations can be printed using the function combo_of_choice(28, TRUE).
  #         We are currently using combinations 25,28,29,and 31 as our four competing models for the spread of agriculture.  
  #
  #    myWorld: Matrix that defines the scope of the available world and acts as a data hub for organizing and reporting      
  #         results from the different elements of the simulation. 
  #
  #    number_of_time_steps: An integer indicating how many iterations the simulation will calculated before writing the data 
  #         file. 
  #
  #    nbs: A list of the available neighbors for each spatial point. This is passed to the function for calculating the interaction 
  #         of neighbors through time. 
  #
  #    number_of_tips: An interger indicating the number of tree tips the simulation should be truncated to. The default is to 
  #         include all the available tips (e.g. 1254 for human languages). 
  #
  # Returns: 
  #    myOut: A list object containing a 'phylo' tree object called mytree in the first position and the myWorld matrix of 
  #         spatial and tree data in the second position 
  #     
  

  x1 <- 4 #Number of runs per core
  sampleer <- sample(c(1,2,5,6), x1)
  #if (replicate_cycle != 1) {
  #  replicate_cycle <- ((replicate_cycle - 1) * x1) + 1
 # }
 # replicate_cycle <- replicate_cycle:(replicate_cycle + (x1 - 1))
  for (count in sampleer) {
  independent <- 1 

    
    # Probability of Arisal
    prob_choose_a <- rev(sort(rexp(4, rate = 9)))
    prob_choose_a <- prob_choose_a[c(sample(1:2, 2), sample(3:4, 2))]
    prob_choose_a[3] <- 0
    P.Arisal0  <- parameters(prob_choose_a[1], prob_choose_a[4],
                             prob_choose_a[3], prob_choose_a[2],
                             "Env_NonD", "Env_D",
                             "Evol_to_F", "Evol_to_D")
    # P.Arisal0 is the one you should change the parameters
    P.Arisal <- matrix(NA, ncol = 2, nrow = nrow(myWorld)) # probability per cell
    colnames(P.Arisal) <- c("Evolve_to_F", "Evolve_to_D")
    Env.Dom <- myWorld[, 7] == 2
    P.Arisal[Env.Dom, 1] <- P.Arisal0[1, 2]
    P.Arisal[!Env.Dom, 1] <- P.Arisal0[1, 1]
    P.Arisal[Env.Dom, 2] <- P.Arisal0[2, 2]
    P.Arisal[!Env.Dom, 2] <- P.Arisal0[2, 1]
    
    colnames(P.Arisal) <- c("Prob_of_Foraging", "Prob_of_Domestication")
    P.Arisal[which(origins == FALSE), 2]  <- 0
    
    #####
    #prob_choose <- runif(12, 0.01, 1)
    #sub <- (prob_choose[1] - 0.01)
    #sub <- ifelse(sub < .1, .1, sub)
    #prob_choose[c(4)] <- runif(1, 0.01, sub)
    #prob_choose[c(5)] <- runif(1, 0.1, 1) # High extinction
    #prob_choose[c(6)] <- runif(1, 0, (prob_choose[3] - 0.01))
    #prob_choose[c(9, 10, 12)] <- runif(3, 0.01, prob_choose[11])
    
    ####
    prob_choose <- runif(12, 0, 1)
    top <- min(prob_choose[c(1,3)], na.rm=TRUE)
    prob_choose[c(2)] <- runif(1, 0, top)
    
    prob_choose[c(5)] <- runif(1, 0, prob_choose[c(2)]) 
    prob_choose[c(6)] <- runif(1, 0, prob_choose[c(5)])
    prob_choose[c(4)] <- runif(1, prob_choose[c(6)], prob_choose[c(5)])
    
        
    if (count == 1) {
      prob_choose[7:12] <- 0
    }
    if (count == 2) {
      prob_choose[9:12] <- 0
    }
    if (count == 3 | count == 5) {
      prob_choose[7:8] <- 0
      independent <- 0
    }
    if (count == 4 | count == 6) {
      independent <- 0
    }
    
    
    P.speciation <- parameters(prob_choose[1], prob_choose[1],
                               prob_choose[2], prob_choose[3],
                               "Env_NonD", "Env_D", "For", "Dom")

    P.extinction  <- parameters(prob_choose[4], prob_choose[4],
                                prob_choose[5], prob_choose[6],
                                "Env_NonD", "Env_D", "For", "Dom")

    
    P.diffusion <- parameters(0, prob_choose[7],
                              prob_choose[8], 0,
                              "Target_For", "Target_Dom",
                              "Source_For", "Source_Dom")
    
    P.TakeOver <- parameters(prob_choose[9], prob_choose[10],
                             prob_choose[11], prob_choose[12],
                             "Target_For", "Target_Dom",
                             "Source_For", "Source_Dom")
    multiplier <- 1 # always 1 now.
   if (count %in% 1:4) { 
        myOut <- RunSimUltimate2(myWorld, P.extinction, P.speciation, P.diffusion, P.Arisal, 
    P.TakeOver, nbs, independent, number_of_time_steps, multiplier, silent = TRUE, 
    count, resolution = seq(1, number_of_time_steps, 100), P.Arisal0, start = NULL)
                            }
   if (count %in% 5:6) {
        myOut <- RunSimUltimate2.push(myWorld, P.extinction, P.speciation, P.diffusion, P.Arisal, 
    P.TakeOver, nbs, independent, number_of_time_steps, multiplier, silent = TRUE, 
    count, resolution = seq(1, number_of_time_steps, 100), P.Arisal0, start = NULL)
                            }
                            
                           
  }
  
}

#####################################################################
coords <- as.matrix(apply(language_centroids[, 3:4], 2, as.numeric)) #coords
conds <- ifelse(suitability2 == 0, 1, 2)
conds[is.na(conds)] <- sample(c(1, 2), sum(is.na(conds)), replace = TRUE) 
origins <- language_centroids[, 5]

##### Specify simulation parameters #################################

number_of_tips <- length(coords[,1])
number_of_time_steps_a <- 50000
#replicate_cycle <- c(1)  #number of replicates
#####################################################################
data("parameters.table")


system.time(
  myWorld <- BuildWorld(coords, conds)
)
number_of_neighbors <- sample(5:9,1)

nbs <- knn2nb(knearneigh(coords, k = number_of_neighbors, longlat = TRUE),
              sym = TRUE) # 7 symmetric neighbors
n.obs <- sapply(nbs, length)
seq.max <- seq_len(max(n.obs))
nbs <- t(sapply(nbs, "[", i = seq.max))

dim(myWorld)


# NAI <- 1000
args <- commandArgs(trailingOnly = FALSE)
print(args)
NAI <- as.numeric(args[7])
#setwd("~/Box Sync/colliding ranges/Simulations_humans/big world cluster outputs")


# Starting point
start <- sample((1:nrow(language_centroids))[as.logical(language_centroids[, 6])], 1)

#sim_run_cluster(replicate_cycle = NAI,
#                myWorld, number_of_time_steps = number_of_time_steps_a, 
#                nbs, number_of_tips = nrow(myWorld), number_of_neighbors= number_of_neighbors, origins=origins,start = start)
install.packages("DiagrammeR")
library(DiagrammeR)

grViz("
  digraph {
    
    node [shape = box
          fontname = Helvetica
          penwidth = 2.0]
    'Input the data hub'; 
    'Is there more than one societ in the world?'; 
    'Pick the only available society';
    'Randomly choos a spreader society';
    'Are there any empty neighboring locations?';
    'Attempt to Takover';
    'Is the spreader a Forager of Domesticator?';
    'is there neighbors with suitable enivonrment for domestication?';
    'Randomly choose a target neighbor';
    'Randomly choose a taret neighbor among the ones with suitable condition for domestication';
    'Randomly choos a number between 0-1. Is this number smaller than the probability of takeover for the confict category**?';
    'Spreader removers target from the space and phylogeny';
    'Nothing happens';
    'Speader occupies the target cell and bifurcate in the phylogeny';
    'Are there any more societies remaining (excluding new societies generated during this loop) that did not go through the expansion process?';
    'Attempt to dispersal';
    'Randomly choos an empty target location';
    'Randomly choos a number between 0-1. Is this number smaller than the probabilityy of speciation for the spreader societ trait in the pre=expanding location environment?';
    'output to data hub';

    edge []
    'Input the data hub' -> 'Is there more than one societ in the world?';
    'Is there more than one societ in the world?' -> 'Pick the only available society' [label = 'NO'];
    'Is there more than one societ in the world?' -> 'Randomly choos a spreader society' [label = 'YES'];
    'Pick the only available society' -> 'Are there any empty neighboring locations?';
    'Randomly choos a spreader society' -> 'Are there any empty neighboring locations?';
    'Are there any empty neighboring locations?' -> 'Attempt to dispersal' [label = 'YES'];
    'Are there any empty neighboring locations?' -> 'Attempt to Takover' [label = 'NO'];
    'Attempt to Takover' -> 'Is the spreader a Forager of Domesticator?';
    'Is the spreader a Forager of Domesticator?' -> 'is there neighbors with suitable enivonrment for domestication?' [label = 'Domesticator'];
    'Is the spreader a Forager of Domesticator?' -> 'Randomly choose a target neighbor' [label = 'Forager'];
    'is there neighbors with suitable enivonrment for domestication?' -> 'Randomly choose a target neighbor' [label = 'NO'];
    'is there neighbors with suitable enivonrment for domestication?' -> 'Randomly choose a taret neighbor among the ones with suitable condition for domestication' [label = 'YES'];
    'Randomly choose a taret neighbor among the ones with suitable condition for domestication' -> 'Randomly choos a number between 0-1. Is this number smaller than the probability of takeover for the confict category**?';
    'Randomly choose a target neighbor'  -> 'Randomly choos a number between 0-1. Is this number smaller than the probability of takeover for the confict category**?' ;
    'Randomly choos a number between 0-1. Is this number smaller than the probability of takeover for the confict category**?' -> 'Spreader removers target from the space and phylogeny' [label = 'YES'];
    'Randomly choos a number between 0-1. Is this number smaller than the probability of takeover for the confict category**?' -> 'Nothing happens' [label = 'NO'];
    'Nothing happens' -> 'Are there any more societies remaining (excluding new societies generated during this loop) that did not go through the expansion process?';
    'Are there any more societies remaining (excluding new societies generated during this loop) that did not go through the expansion process?' ->  'output to data hub' [label = 'NO'];
    'Attempt to dispersal' -> 'Randomly choos an empty target location';
    'Randomly choos an empty target location' -> 'Randomly choos a number between 0-1. Is this number smaller than the probabilityy of speciation for the spreader societ trait in the pre=expanding location environment?';
    'Randomly choos a number between 0-1. Is this number smaller than the probabilityy of speciation for the spreader societ trait in the pre=expanding location environment?' -> 'Speader occupies the target cell and bifurcate in the phylogeny' [label = 'YES'];
    'Randomly choos a number between 0-1. Is this number smaller than the probabilityy of speciation for the spreader societ trait in the pre=expanding location environment?' -> 'Nothing happens' [label = 'NO'];
  'Are there any more societies remaining (excluding new societies generated during this loop) that did not go through the expansion process?' ->  'Is there more than one societ in the world?' [label = 'YES'];
  'Speader occupies the target cell and bifurcate in the phylogeny' -> 'Are there any more societies remaining (excluding new societies generated during this loop) that did not go through the expansion process?';
  'Spreader removers target from the space and phylogeny' -> 'Speader occupies the target cell and bifurcate in the phylogeny';
  }")

Module 1: Simulation to produce a world and a tree

# Install the most recent version of FARM from a .zip file
install.packages(file.choose(), repos=NULL) 
library(FARM)
ls("package:FARM")

Inputs

Module 1 functions

The first set of RunSim functions are the default pipeline where only one output is saved at the end of the simulation.

This first function controls error messages coming from the primary function below.

# Run the simulation function skiping the erros and atributing NA if it occurs
RunSimUltimate <- function(myWorld, P.extinction, P.speciation,
                           P.diffusion, P.Arisal, P.TakeOver, nbs, independent,
                           N.steps, multiplier,
                           silent = TRUE, start = NULL) {

  result <- try(RunSim(myWorld, P.extinction, P.speciation,
                       P.diffusion, P.Arisal, P.TakeOver, nbs,
                       independent, N.steps,
                       multiplier, start = start), silent = silent)
  if (class(result) == "try-error") {
    result <- NA
  }
  return(result)
}

This is the primary function running the simulation.

#==================================================================
# SimulationFunctions.R
#
# Contains a function for simulation of cultural evolution in space and time
# Allows for (1) Vertical Transmission (phylogenetic inheritance); (2) Horizontal
# Transmission (cultural diffusion); (3) Ecological selection (Both speciation and
# extinction are determined by the match between the state of a binary trait and the
# environment a societuy occupies).
#
# 7 Jun 2016
# Carlos A. Botero, Bruno Vilela & Ty Tuff
# Washington University in Saint Louis
#==================================================================
RunSim <- function(myWorld, P.extinction, P.speciation,
                   P.diffusion, P.Arisal, P.TakeOver, nbs, independent,
                   N.steps, multiplier, start) {
  # myWorld = The hexagonal world created with the function BuildWorld
  # P.extinction = Probability matrix of extinction
  # P.speciation = Probability matrix of speciation
  # P.diffusion = Probability matrix of diffusion
  # P.Arisal = Probability matrix of arisal
  # P.TakeOver = Probability matrix of takeover
  # N.steps = Number of steps in the model
  # multiplier = The number that will multiply the probabilities according
  # to environmetal fitness.
  # start = the point ID in 'myWorld' that will give risen to humans.
  # (humans origin will be in one of the existing positions)

  world.size <- nrow(myWorld)
  # Initialize parameters we will use later to build the phylogeny
  rootnode <-  world.size + 1 # standard convention for root node number

  # set the seed for simulation
  if (is.null(start)) {
  start <- sample(1:world.size, 1)
  }

  myWorld[start, 4:6] <- c(0, 0, 1) # Setting root(0), time(0), ancestral(1, forager)

  mytree <- TheOriginOfSpecies(world.size, start) # Empty tree
  myT <- 0 # Time starts at zero

  # Common input and output for all the internal modules
  input <- list(P.speciation, P.Arisal, P.diffusion, P.extinction, P.TakeOver,
                myWorld, mytree, myT, multiplier, nbs, independent)

  # Functions order to be randomized
  rand_order_func_run <- list("Extinction", "Diffusion", "SpeciationTakeOver", "Arisal")

  cat("0% [") # Time count

  for (steps in 1:N.steps) { # Starts the loop with 'n' steps

    if (steps %% round((N.steps / 10)) == 0) { # Time count
      cat('-') # Time count
    }# Time count
    if (steps == N.steps) { # Time count
      cat("] 100 %\n")# Time count
    }# Time count

    # Randomize functions order
    rand_order <- sample(rand_order_func_run)
    # Run the functions
    input <- do.call(rand_order[[1]], list(input = input))
    input <- do.call(rand_order[[2]], list(input = input))
    input <- do.call(rand_order[[3]], list(input = input))
    input <- do.call(rand_order[[4]], list(input = input))

  }
  # Trunsform the input/output into the final result and return it
  myWorld <- as.data.frame(input[[6]])
  myWorld[, 8] <- paste0("t", myWorld[, 8])
  mytree <- makePhy(input[[7]])
  mytree$edge.length <- mytree$edge.length / N.steps
  return(list('mytree' = mytree, 'myWorld' = myWorld))
}

Push versions

# Run the simulation function skiping the erros and atributing NA if it occurs
RunSimUltimate.push <- function(myWorld, P.extinction, P.speciation,
                                P.diffusion, P.Arisal, P.TakeOver, nbs, independent,
                                N.steps, multiplier,
                                silent = TRUE, start = NULL) {

  result <- try(RunSim.push(myWorld, P.extinction, P.speciation,
                            P.diffusion, P.Arisal, P.TakeOver, nbs,
                            independent, N.steps,
                            multiplier, start = start), silent = silent)
  if (class(result) == "try-error") {
    result <- NA
  }
  return(result)
}
#==================================================================
# SimulationFunctions.R
#
# Contains a function for simulation of cultural evolution in space and time
# Allows for (1) Vertical Transmission (phylogenetic inheritance); (2) Horizontal
# Transmission (cultural diffusion); (3) Ecological selection (Both speciation and
# extinction are determined by the match between the state of a binary trait and the
# environment a societuy occupies).
#
# 7 Jun 2016
# Carlos A. Botero, Bruno Vilela & Ty Tuff
# Washington University in Saint Louis
#==================================================================
RunSim.push <- function(myWorld, P.extinction, P.speciation,
                   P.diffusion, P.Arisal, P.TakeOver, nbs, independent,
                   N.steps, multiplier, start) {
  # myWorld = The hexagonal world created with the function BuildWorld
  # P.extinction = Probability matrix of extinction
  # P.speciation = Probability matrix of speciation
  # P.diffusion = Probability matrix of diffusion
  # P.Arisal = Probability matrix of arisal
  # P.TakeOver = Probability matrix of takeover
  # N.steps = Number of steps in the model
  # multiplier = The number that will multiply the probabilities according
  # to environmetal fitness.
  # start = the point ID in 'myWorld' that will give risen to humans.
  # (humans origin will be in one of the existing positions)

  world.size <- nrow(myWorld)
  # Initialize parameters we will use later to build the phylogeny
  rootnode <-  world.size + 1 # standard convention for root node number

  # set the seed for simulation
  if (is.null(start)) {
    start <- sample(1:world.size, 1)
  }

  myWorld[start, 4:6] <- c(0, 0, 1) # Setting root(0), time(0), ancestral(1, forager)

  mytree <- TheOriginOfSpecies(world.size, start) # Empty tree
  myT <- 0 # Time starts at zero

  # Common input and output for all the internal modules
  input <- list(P.speciation, P.Arisal, P.diffusion, P.extinction, P.TakeOver,
                myWorld, mytree, myT, multiplier, nbs, independent)

  # Functions order to be randomized
  rand_order_func_run <- list("Extinction", "Diffusion",
                              "SpeciationTakeOver.push", "Arisal")

  cat("0% [") # Time count

  for (steps in 1:N.steps) { # Starts the loop with 'n' steps

    if (steps %% round((N.steps / 10)) == 0) { # Time count
      cat('-') # Time count
    }# Time count
    if (steps == N.steps) { # Time count
      cat("] 100 %\n")# Time count
    }# Time count

    # Randomize functions order
    rand_order <- sample(rand_order_func_run)
    # Run the functions
    input <- do.call(rand_order[[1]], list(input = input))
    input <- do.call(rand_order[[2]], list(input = input))
    input <- do.call(rand_order[[3]], list(input = input))
    input <- do.call(rand_order[[4]], list(input = input))

  }
  # Trunsform the input/output into the final result and return it
  myWorld <- as.data.frame(input[[6]])
  myWorld[, 8] <- paste0("t", myWorld[, 8])
  mytree <- makePhy(input[[7]])
  mytree$edge.length <- mytree$edge.length / N.steps
  return(list('mytree' = mytree, 'myWorld' = myWorld))
}

Module 2: Space and phylogeny summary statistics

This is the master document for Module 2, a foundational function in our FARM package that analyzes results from Module 1, the other foundational function. Module 1 simulates a spatial pattern and a phylogenetic tree given a set of environmental and inheritance rules and then Module 2 summarizes those simulated results using a large set of targeted summary statistics. Here we describe our choice of summary statistics, justify those choices as part of a larger theoretical context, and provide our reproducable code for executing the anaylses yourself. These two parts are seperated into modules so that they can act independently. An combination of spatial pattern and associated phylogeny many be used as long as they are formatted correctly.

This pipeline was designed to analyze a simulated world where all the information is known about both the world and the tree. There is no missing information, just extinct trees. This is much different than our real tree that has loads of uncertainty unevenly destributed across it. The result you see demonstrated right now are one simulated result of many. I need to do a sister page to this were we do this entire analysis on the real tree, or best real tree we’ve got.

We have four types of data available for asking research questions using D-place data: phylogenies, spatial locations, trait identities, and environmental reconstructions. Any one of these four data types alone are relatively information poor, so we are searching for ways to model connections between these data types to draw stronger conclusions overall.

Other modules can use the summary statistics generated from this module to test hypotheses. We currently have a ABC and Random Forest module started but there will be more to come.

These are quantitative connections that we are assumed in the analyses, but we don’t actually have any support in the data for doing so. 1. nearest neighbor connectivity measures 2. Abundance estimates 3. Pairwise influence (history) between cultures. 4. Environmental reconstruction validation evidence

Phylogenetic summary statistics

Whole tree vs. part of tree? These statistics are generally used to compare one sample to another. For example, an experimental contrast between two sites, two phylogenetic groups, or two communities in two different locations. Here we are calculating these statistics for the global langauage tree to compare against global trees created in our simulation. You still retain the ability to subset this tree or others and send only those subsets through this code to compare the values with each other afterwards.

  1. Branch Length (richness and divergence)
  2. Pairwise distance between tips (richness, divergence, and regularity)
  3. Phylogenetic isolation (divergence, and regularity)
  4. Nearest Neighbor (divergence, and regularity)

All trees are ultrametric.

Introduction and framework

The choice of phylogenetic analyses and organizational scheme is based on the suggestions of Tucker et al. (2016). Here are a few images from that paper for an overview:

From Tucker et al. (2016) From Tucker et al. (2016)

From Tucker et al. (2016)

From Tucker et al. (2016)

From Tucker et al. (2016)

From Tucker et al. (2016)

library(knitr)
library(phytools)
library(FARM)
library(ROCR)
library(spdep)
load('~/Downloads/download.Rdata')

this_tree <- myOut$mytree
this_world <- myOut$myWorld
str(this_world)
str(this_tree)

Alpha diversity metrics

Branch Lengths

Branch length data is embedded in the tree object provided to this function. The first step in summarizing the lengths is to extract those data from the tree object. These data are called ‘edges’ in the tree object. We extract branch lengths and create an object called ‘Branch_lengths’ for passing on to the other summary functions. The histogram below shows the frequency of different branch lengths found throughout the tree.

Branch_Lengths <- this_tree$edge.length

We can summarize branch lengths according to normal summary statistics, but it can be difficult to assign evolutionary meaning to some of these metrics and so they are not regularly used as best I can tell. This lack of meaning does not mean that these statistics couldn’t be used to distinguish between large simulated trees.

mean_branch_length <- mean(Branch_Lengths)
variance_branch_length <- var(Branch_Lengths)
SD_branch_length <- sd(Branch_Lengths)

Phylogenetic diversity (\(PD\))

Phylogenetic diversity (\(PD\)) is the summation (\(\sum\)) of all branch lengths connecting species together, where \(B_{t}\) is the set of included tips and \(L_{b}\) is Branch lengths (Faith 1992). This is an anchor test, which means it is regularly used, well understood, and we should use it to anchor our work to past work. PD is a richness measure, it tells us how much evolutionary history is associated with a set of tips.

\[PD = \sum_{b \in B_{t}}^{}L_{b}\]

# Anchor test = PD (Faith's phylogenetic diversity)
Pylo_diversity_is_sum_of_BL <- sum(Branch_Lengths)
Pylo_diversity_is_sum_of_BL

There are variations on this measure that we have NOT implemented here. It is popular to scale this measure according to some ecological driver. Barker (2002) scales branch lengths (\(L_{b}\)) by multiplying them against the abundance of individuals at at tip (\(A_{b}\)). Others (D. F. Rosauer et al. 2009), scale them by their range size instead (\(R_{b}\)).

\[\Delta n PD = \sum_{b \in B_{t}}^{}A_{b}L_{b}\] \[PE = \sum_{b \in B_{t}}^{}\dfrac{L_{b}}{R_{b}}\] Argueing that proportional abundance phylogenetic diversity (\(PD_{Ab}\)) is more effective than the standard PD calculated from raw abundance, Vellend et al. (2011) penned a new version of PD where \(B\) is the total number of branch lengths (\(L_{b}\)). Note: We don’t have abundance data right now for the human project so this metric is not currently very helpful.
\[PD_{Ab} = B * \dfrac{\sum_{b \in B_{t}}^{}A_{b}L_{b}}{\sum_{b \in B_{t}}^{}A_{b}}\]

#Calculate B
number_of_branches <- length(Branch_Lengths)
number_of_branches

Average phylogenetic diversity (\(avPD\))

Average phylogenetic diversity (\(avPD\)) (Clarke and Warwick 2001) is a branch length-based divergence indices where PD is divided by the total number of tips (\(S\)) in the tree. \[avPD = \dfrac{PD}{S}\]

Number_of_tips <- length(this_tree$tip.label)
average_phylogenetic_diversity <- Pylo_diversity_is_sum_of_BL / Number_of_tips
average_phylogenetic_diversity

There is also a proportional abundance version of average phylogenetic diversity (\(avPD_{Ab}\)) (Tucker et al. 2016). Again, we don’t have abundance values yet for D-place. \[avPD_{Ab} = \dfrac{B * \dfrac{\sum_{b \in B_{t}}^{}A_{b}L_{b}}{\sum_{b \in B_{t}}^{}A_{b}}}{S}\]

Pairwise distance between tips

This is the patristic distance, the sum of the branch lengths following the shortest distance between two tips in a tree, implemented as a distance matrix where every tip is compared to every other tip. This distance function can be anything. We use euclidean and environmental distance matrices heavily in the spatial analyses.

Calculate the patristic distance between two taxa, for all taxa

Calculate the patristic distance between two taxa using the R package ‘phytools’, this function takes a ‘phylo’ tree object and returns a distance matrix between tips. Need original citation.

## Pairwise distance between tips - From library(ape) in library(phytools)
Pairwise_dist <- cophenetic(this_tree)

yields a distance matrix (list of 2D matrices) of all distances between taxa.

Sum of all pairwise distances (\(F\))

Now we can use a set of summary statistics to describe those pairwise distances. The sum of all pairwise distances, \(F\), is formally called ‘Extensive quadratic entropy’. (???). Just as it was with branch lengths, this is a richness measure and, accordingly, should be used to answer richness questions.

\[F = \sum_{i} \sum_{j} d_{ij}\]

# F -- Extensive quadratic entropy
F_quadratic_entropy_is_sum_of_PD <- sum(Pairwise_dist)
F_quadratic_entropy_is_sum_of_PD

Mean pairwise distance (MPD)

Mean inter-species distances. The mean of all pairwise distances, \(MPD\) (a.k.a. \(AvTD\), and \(\Delta^{+}\)), is the mean distance between species. (Clarke and Warwick 1998; Webb et al. 2002; Webb, Ackerly, and Kembel 2008; Kembel et al. 2010). \[MPD = \dfrac{\sum_{ij} d_{ij}}{S(S-1)}\]

# Anchor test = MPD (mean pairwise distance)
Mean_pairwise_distance <- 
  Pairwise_dist / (Number_of_tips * (Number_of_tips - 1) ) 

MPD anchored to the root

There is an extention to mean pairwise distance calculations from Helmus et al. (2010) called \(PSV\), \(PSR\), and \(PSE\), phylogenetic species variability, phylogenetic species richness, and phylogenetic species evenness. These measures take the basic pairwise distance calculations and anchor them to the root of the tree so distances have a common denominator. This extention is implemented by using the same equations, just with a constrained set of \(d_{ij}\) conditions. Specifically,

\[PSV = MPD = \dfrac{\sum_{ij} d_{ij}}{S(S-1)}\] \[PSR = \sum_{i} {(\dfrac{1}{S-1} \sum_{j} {d_{ij}})}\] \[PSE = \dfrac{S}{S-1} \sum_{ij} d_{ij}p_{i}p_{j}\]

with these specific values of \(d_{ij}\)

\[ d_{ji}=0.5*(c_{ii} + c_{jj} - c_{ij}) \\ \ \\ or \\ \ \\ d_{ij} = 1 - c_{ij} / (\sqrt{c_{ii}c_{jj}}) \] and \[ c_{ii} = the \ sum \ of \ branch \ lengths \ from \ tip \ i \ to \ the \ root \ of \ the \ phylogenetic \ tree. \\ \ \\ c_{ij} = the \ sum \ of \ branch \ lengths \ from \ first \ common \ ancestor \ for \ i \ and \ j \ to \ the \ root. \]

Average distance between two randomly chosen species

\(J\), Intensive quadratic entropy, which is the average distance between two randomly chosen species (???) \[J = \dfrac{\sum_{ij}d_{ij}}{S^2} \]

Simpson’s diversity index for pairwise distance

There has been a long effort to pen a phylogenetic analogy to a Simpson’s diversity index. (Rao 1982; Clarke and Warwick 1998; S. Ã. Pavoine, Ollier, and Pontier 2005; Hardy and Senterre 2007; Webb et al. 2002; Webb, Ackerly, and Kembel 2008; Kembel et al. 2010). The conclusion seems to be that this measure is equivilent to scaling \(MPD\) by abundance \(p_{i}\) and \(p_{j}\) to get \(MPD_{Ab}\). This is also a special case of Rao’s Quadratic Entropy, \(Roe's QE\). Note: not using abundance measures yet for D-place data.

\[MPD_{Ab} = \sum_{i} \sum_{j} d_{ij} p_{i} p_{j}\]

Interspecific comparisons of pairwise distances

The interspecific variant (rather than the intraspecific default described above) defines the expected phylogenetic distance between two indivdiuals randomely drawn conditionally on the fact that they indivdulas from different species. \[InterMPD_{Ab} = \dfrac{\sum_{i} \sum_{j \ne i} d_{ij} p_{i} p_{j} }{\sum_{i} \sum_{j \ne i} d_{ij} p_{i} p_{j}} \]

Variance in pairwise distances (\(VPD\))

Variance in pairwise distances, \(VPD\) (a.k.a. \(VarTD\) and \(\Lambda^+\)), is a regularity indices. Clarke and Warwick (2001) Variance is relative to tips, \(S\), not to total branches (\(B\) from above). These are the residuals, they compare each individual pairwise connection to the overall mean.

\[VPD = \dfrac{1}{S(S-1)} (\sum_{i} \sum_{j \ne i} {(d_{ij} - MPD)^2})\]

#need to adjust to equation above!

#Pairwise distance/all distances -- Variance of pairwise distances

# Anchor test = VPD (variation of pairwise distance)  

variance_pairwise_distance <- var(as.vector(Pairwise_dist))

Variants of \(VPD\) are \(VPD_{ab}\) and \(InterPVD_{Ab}\), where variance is scaled by abundance or compared in and out of species. These are also regularity indices.

\[ VPD_{Ab}= (\sum_{i} \sum_{j} n_{i} n_{j}) * \dfrac{\sum_{i} \sum_{j} n_{i} n_{j} (d_{ij} - MPD_{Ab})^2} {(\sum_{i} \sum_{j} n_{i} n_{j})^2 - \sum_{i} \sum_{j} (n_{i} n_{j})^2} \\ or \\ InterVPD_{Ab} = (\sum_{i} \sum_{j \ne i} n_{i} n_{j}) * \dfrac{\sum_{i} \sum_{j \ne i} n_{i} n_{j} (d_{ij} - InterMPD_{Ab})^2} {(\sum_{i} \sum_{j \ne i} n_{i} n_{j})^2 - \sum_{i} \sum_{j \ne i} (n_{i} n_{j})^2} \]

Nearest phylogenetic neighbor

Divergence indices

Divergence indices using nearest distance: \(MNTD\) and \(MNTD_{Ab}\), Mean nearest taxon distance and Abundance-weighted MNTD (Webb et al. 2002; Webb, Ackerly, and Kembel 2008; Kembel et al. 2010).

\(MNTD\), mean nearest taxon distance, is the mean shortest distance from a species to all other in the assemblage (Webb et al. 2002; Webb, Ackerly, and Kembel 2008; Kembel et al. 2010).
\[ MNTD = \dfrac{1}{S} \sum_{i} d_{i_{min}} \]

\(MNTD_{AB}\), abundance adjusted mean nearest taxon distance. Adjusted by species proportions (i.e. species’ relative abundances) (Webb et al. 2002; Webb, Ackerly, and Kembel 2008; Kembel et al. 2010)
\[ MNTD_{Ab} = \sum_{i=1}^{S} [d_{i_{min}} * p_{i}] \]

Regularity indices

Regularity indices using nearest distances: \(VNTD\), \(VNTD_{Ab}\), \(PE_{ev}\).

\(VNTD\), Variance in nearest taxon distances, is the variance in nearest pairwise distance (Tucker et al. 2016). \[ VNTD = \dfrac{1}{S} \sum_{i-1}^{S} [(d_{i_{min}} - MNTD)^2] \] \(VNTD_{Ab}\), Abundance weighted variance in nearest taxon distances, is scales by abundance in the same way as descried above (Tucker et al. 2016). \[ VNTD_{Ab} = \dfrac {(\sum_{i} n_{i}) \sum_{i} n_{i} (d_{i_{min}} - MNTD_{Ab})^2} {(\sum_{i} n_{i})^2 - \sum_{i} n_{i} ^2} \]

Phylogenetic version of the funtional \(FE_{ve}\) index

\(PE_{ve}\), phylogenetic evenness is a phylogenetic version of the funtional \(FE_{ve}\) index. First a minimum spanning tree (\(MST\)) is computed using the cophenetic distance obtained from the phylogenetic tree. The \(MST\) contains \(S-1\) Branches connection the \(S\) species. We denote \(l\) a branch on the \(MST\), \(dist(i,j)\) is the length the branch \(l\) that connects species \(i\) and \(j\). \(n_{i}\) is, as defined above, the abundance of species \(i\) in the asseblage (Villeger, Mason, and Mouillot 2008; Dehling et al. 2014).

\[ Weighted \ evenness: \\ EW_{i} = \dfrac{dist(i,j)} {(n_{i} + n_{j})/(\sum_{k=1}^{S}n_{k})} \\ \ \\ Partial \ weighted \ evenness: \\ PEW_{l} = \dfrac {EW_{l}} {\sum_{l=1}^{S-1} EW_{l}} \\ \ \\ Phylogenetic \ evenness: \\ PE_{ve} = \dfrac {\sum_{l=1}^{S-1} min(PEW_{l}, \dfrac{1}{S-1}) - (\dfrac{1}{S-1})} {1- (\dfrac{1}{S-1})} \]

Phylogenetic isolation

A phylogenetic isolation index represents the relative isolation of a given species within a phylogenetic tree. Several indices have been proposed so far but we focus here on the evolutionary distinctiveness index called ‘Fair Proportion’ as proposed by (???) and Isaac et al. (2007).

Evolutionary distinctiveness (richness indices)

\(ED\), evolutionary distinctiveness is a richness indices. NOTE: not equal to Faith’s PD because the \(ED_{i}\) are computed from the regional pool of species and sumed across a given assemblage (i.e. a subset of the regional species pool) (Tucker et al. 2016; Safi et al. 2013; ???; Isaac et al. 2007).

\[ ED = \sum_{i}ED_{i} \\ \ \\ where \ ED_{i} = \sum_{b \in B_{t_{i}}} \dfrac{L_{b}}{S_{b}} \]

\(AED\), Abundance-weighted \(ED\) (Tucker et al. 2016; Cadotte et al. 2010). \[ \sum_{i} AED_{i} \\ \ \\ where \ AED_{i} = \sum_{b \in B_{t_{i}}} \dfrac{L_{b}}{A_{b} }* p_{i} \]


# Bruno's function for ED. Provided in library(FARM)

evol.distinct2 <- function (tree, type = c("equal.splits", "fair.proportion"), 
    scale = FALSE, use.branch.lengths = TRUE) 
{
    type <- match.arg(type)
    if (is.rooted(tree) == FALSE) 
        warning("A rooted phylogeny is required for meaningful output of this function", 
            call. = FALSE)
    if (scale == TRUE) {
        if (is.ultrametric(tree) == TRUE) 
            tree$edge.length <- tree$edge.length/(as.numeric(branching.times(tree)[1]))
        else tree$edge.length <- tree$edge.length/sum(tree$edge.length)
    }
    if (use.branch.lengths == FALSE) 
        tree$edge.length <- rep(1, length(tree$edge.length))
    for (i in 1:length(tree$tip.label)) {
        spp <- tree$tip.label[i]
        nodes <- .get.nodes(tree, spp)
        nodes <- nodes[1:(length(nodes) - 1)]
        internal.brlen <- tree$edge.length[which(tree$edge[, 
            2] %in% nodes)]
        if (length(internal.brlen) != 0) {
            internal.brlen <- internal.brlen * switch(type, equal.splits = sort(rep(0.5, 
                length(internal.brlen))^c(1:length(internal.brlen))), 
                fair.proportion = {
                  for (j in 1:length(nodes)) {
                    sons <- .node.desc(tree, nodes[j])
                    n.descendents <- length(sons$tips)
                    if (j == 1) portion <- n.descendents else portion <- c(n.descendents, 
                      portion)
                  }
                  1/portion
                })
        }
        ED <- sum(internal.brlen, tree$edge.length[which.edge(tree, 
            spp)])
        if (i == 1) 
            w <- ED
        else w <- c(w, ED)
    }
    return(w)
}

Evolutionary distinctiveness is our basic measure of phylogenetic isolation. #This should likely be ‘fair proportions’ instead of ‘equal.splits’.


# Calculate ED
# Using equal.splits method, faster computation
# Evolutionary_distinctiveness_i <- evol.distinct2(this_tree, type = "equal.splits")  

# ED - Summed evolutionary distinctiveness
# Evolutionary_distinctiveness_sum <- sum(Evolutionary_distinctiveness_i)
#Evolutionary_distinctiveness_sum

We can run some standard summary statistics (mean and variance) on this ED measure. var(Ed) shows up close to VPD on the PCAs in the intro (Tucker et al. 2016).

# mean(ED)
# mean_Phylogenetic_isolation <- mean(Evolutionary_distinctiveness_i)

# var(ED)
#variance_Phylogenetic_isolation <- var(Evolutionary_distinctiveness_i)
#mean_Phylogenetic_isolation
#variance_Phylogenetic_isolation

Mean evolutionary distinctiveness (divergence indices)

The divergence indices version for \(ED\) is mean evolutionary distinctiveness, \(MED\). The mean of evolutionary distinctiveness (???; Isaac et al. 2007). \[ MED = \dfrac {\sum_{i} ED_{i}} {S} \\ \ \\ with \\ \ \\ ED_{i} = \sum_{b \in B_{t_{i}}} \dfrac{L_{b}}{S_{b}} \] #### Entropy measure of evolutonary distinctiveness (regularity indices) The regularity indices for \(ED\)/phylogenetic isolation are \(H_{ED}\), \(E_{ED}\), \(var(ED)\), \(H_{AED}\)

\(H_{ED}\), Entropy measure of evolutionary distinctiveness, is the shannon index applied to evolutionary distinctiveness values (Cadotte et al. 2010). \[ H_{ED} = -\sum_{i=1}^{S} ((\dfrac{ED_{i}}{\sum_{i=1}^{S} ED_{i}}) * \ln (\dfrac{ED_{i}}{\sum_{i=1}^{S} ED_{i}})) \]

\(E_{ED}\), Equitability of evolutionary distinctiveness, is \(H_{ED}\) controlled for species richness (Cadotte et al. 2010).

\[ E_{ED} = \dfrac{H_{ED}}{\ln(S)} \] \(var(ED)\), Variance in evolutinoary distinctiveness, is the variance of species evolutionary distinctiveness (Tucker et al. 2016).

\[ var(ED) = \dfrac{1}{S-1} * \sum_{i=1}^{S} (ED_{i}-\dfrac{\sum_{i=1}^{S} ED_{i}}{S})^2 \] \(H_{ED_{Ab}}\), Abundance-weighted version of \(H_{ED}\) (Cadotte et al. 2010).

\[ H_{ED_{Ab}} = -\sum_{i=1}^{S} (\dfrac{n_{i}AED_{i}}{\sum_{i=1}^{S} n_{i}AED_{i}} * \ln(\dfrac{n_{i}AED_{i}}{\sum_{i=1}^{S} n_{i}AED_{i}})) \]

Beta diversity

We currently are not using any beta diversity metrics but there are many to choose from if we decide to add them later.

Tree topology

Tree topology is a measure of the shape of the overall tree. The tree can be lopsided side-to-side or front-to-back.

Our most trusted index for the tippy vs trunky of a tree is the gamma index, \(\gamma\).The index characterizes the distribution of branching events within the tree. Trees with γ < 0 have relatively longer branches towards the tips of the phylogeny (tippy trees), whereas trees with γ > 0 have relatively longer inter-nodal distances towards the root of the phylogeny (stemmy trees). tk represents an ‘evolutionary period’ (limits are given by two speciation events) or equivalently an internode distance (Pybus and Harvey 2000).

\[ \gamma = \dfrac {(\dfrac{1}{S-2}* \sum_{i=2}^{S-1} (\sum_{k=2}^{i} Kt_{k}))- \dfrac{1}{2} * \sum_{j=2}^{S} jt_{j}} {(\sum_{j=2}^{S} jt_{j}) * \sqrt{\dfrac{1}{12*(S-2)}}} \]

# ltt function from library(phytools)
ltt <- function (tree, plot = TRUE, drop.extinct = FALSE, log.lineages = TRUE, 
    gamma = TRUE, ...) 
{
    tol <- 1e-06
    if (!inherits(tree, "phylo") && !inherits(tree, "multiPhylo")) 
        stop("tree must be object of class \"phylo\" or \"multiPhylo\".")
    if (inherits(tree, "multiPhylo")) {
        obj <- lapply(tree, ltt, plot = FALSE, drop.extinct = drop.extinct, 
            log.lineages = log.lineages, gamma = gamma)
        class(obj) <- "multiLtt"
    }
    else {
        tree <- reorder.phylo(tree, order = "cladewise")
        if (!is.null(tree$node.label)) {
            node.names <- setNames(tree$node.label, 1:tree$Nnode + 
                Ntip(tree))
            tree$node.label <- NULL
        }
        else node.names <- NULL
        if (is.ultrametric(tree)) {
            h <- max(nodeHeights(tree))
            time <- c(0, h - sort(branching.times(tree), decreasing = TRUE), 
                h)
            nodes <- as.numeric(names(time)[2:(length(time) - 
                1)])
            ltt <- c(cumsum(c(1, sapply(nodes, function(x, y) sum(y == 
                x) - 1, y = tree$edge[, 1]))), length(tree$tip.label))
            names(ltt) <- names(time)
        }
        else {
            drop.extinct.tips <- function(phy) {
                temp <- diag(vcv(phy))
                if (length(temp[temp < (max(temp) - tol)]) > 
                  0) 
                  pruned.phy <- drop.tip(phy, names(temp[temp < 
                    (max(temp) - tol)]))
                else pruned.phy <- phy
                return(pruned.phy)
            }
            if (drop.extinct == TRUE) 
                tree <- drop.extinct.tips(tree)
            root <- length(tree$tip) + 1
            node.height <- matrix(NA, nrow(tree$edge), 2)
            for (i in 1:nrow(tree$edge)) {
                if (tree$edge[i, 1] == root) {
                  node.height[i, 1] <- 0
                  node.height[i, 2] <- tree$edge.length[i]
                }
                else {
                  node.height[i, 1] <- node.height[match(tree$edge[i, 
                    1], tree$edge[, 2]), 2]
                  node.height[i, 2] <- node.height[i, 1] + tree$edge.length[i]
                }
            }
            ltt <- vector()
            tree.length <- max(node.height)
            n.extinct <- sum(node.height[tree$edge[, 2] <= length(tree$tip), 
                2] < (tree.length - tol))
            node.height[tree$edge[, 2] <= length(tree$tip), 2] <- node.height[tree$edge[, 
                2] <= length(tree$tip), 2] + 1.1 * tol
            time <- c(0, node.height[, 2])
            names(time) <- as.character(c(root, tree$edge[, 2]))
            temp <- vector()
            time <- time[order(time)]
            time <- time[1:(tree$Nnode + n.extinct + 1)]
            for (i in 1:(length(time) - 1)) {
                ltt[i] <- 0
                for (j in 1:nrow(node.height)) ltt[i] <- ltt[i] + 
                  (time[i] >= (node.height[j, 1] - tol) && time[i] <= 
                    (node.height[j, 2] - tol))
            }
            ltt[i + 1] <- 0
            for (j in 1:nrow(node.height)) ltt[i + 1] <- ltt[i + 
                1] + (time[i + 1] <= (node.height[j, 2] + tol))
            names(ltt) <- names(time)
            ltt <- c(1, ltt)
            time <- c(0, time)
            time[length(time)] <- time[length(time)] - 1.1 * 
                tol
        }
        if (!is.null(node.names)) {
            nn <- sapply(names(time), function(x, y) if (any(names(y) == 
                x)) 
                y[which(names(y) == x)]
            else "", y = node.names)
            names(ltt) <- names(time) <- nn
        }
        if (gamma == FALSE) {
            obj <- list(ltt = ltt, times = time, tree = tree)
            class(obj) <- "ltt"
        }
        else {
            gam <- gammatest(list(ltt = ltt, times = time))
            obj <- list(ltt = ltt, times = time, gamma = gam$gamma, 
                p = gam$p, tree = tree)
            class(obj) <- "ltt"
        }
    }
    if (plot) 
        plot(obj, log.lineages = log.lineages, ...)
    obj
}
<environment: namespace:phytools>
ltts <- ltt(this_tree, gamma = TRUE, plot = FALSE)
ltts
str(ltts)
lineages_through_time <- as.numeric(ltts[[1]])
time_steps <- as.numeric(ltts[[2]])
#extract Gamma index
gamma <- ltts[[3]]
gamma_p_value <- ltts[[4]]
lineages_through_time 
time_steps 
gamma 
gamma_p_value 

There are two other regularly used metrics that include abundance measures. Note: we don’t have abundance measures for D-place data.

\(IAC\), imbalance of abundance at the clade level, quantifies the relative deviation in the abundance distribution from a null case where individuals are evenly partitioned between clade splits. \(v\) is the number of nodes in the phylogenetic tree. \(n_{i}\) is, as defined above, the abundance of species \(i\) in the assemblage. \(\eta_{k}\) is the expected abundance species \(i\) would have if the abundance was randomly split among lineages in the phylogenetic tree at each speciation event. is the number of lineages originating at node \(k\) in the set \(s(k,root)\), which contains the nodes located on the path between node \(k\) and the root of the phylogenetic tree. N is the total assemblage abundance (Cadotte et al. 2010).

\[ \dfrac{\sum_{i=1}^{S} |n_{i} - \hat{n_{i}}|} {v} \\ \ \\ where \\ \ \\ \hat{n_{i}} = \dfrac{N}{\prod_{K \in s(i, root)}\eta_{k}} \]

\(I_{c}\), the Colless index, is the sum of the absolute differences in species richness between sister-clades at each internal node. For fully resolved trees, each internal node defines two sister-clades. \(S_{1k}\) is the number of species descending from the first clade defined by node k and \(S_{2k}\) that of the second clade. \(v\) is, as defined above, the number of nodes in the phylogenetic (Colless 1982).

\[ I_{c} = \sum_{k=1}^{v} |S_{1k} - S_{2k}| \]

Macroevolutionary rates


#function name = bd, function input = tree of type 'phylo'
bd <- function (tree) 
{
    tree$edge.length <- tree$edge.length/max(tree$edge.length)
    x <- birthdeath(tree)
    b <- x$para[2]/(1 - x$para[1])
    d <- b - x$para[2]
    c(setNames(c(b, d), c("b", "d")), x$para)
}
<environment: namespace:FARM>
 ## Speciation vs extinction rates and Net diversification
bds <- bd(this_tree)
speciation_rate <- bds[1]
extinction_rate <- bds[2]
extinction_per_speciation <- bds[3]
speciation_minus_extinction <- bds[4]
  
## Speciation vs extinction rates and Net diversification dependent on trait
# N.for.dom <- table(this_world[, 6])
#    if(length(N.for.dom) == 2) {
par.div.dep <- DivDep( mytree = this_tree, myWorld = this_world)
trait_1_speciation <- par.div.dep[1]
trait_2_speciation <- par.div.dep[2]
trait_1_extinction <- par.div.dep[3]
trait_2_extinction <- par.div.dep[4]
transition_from_trait_1_to_2 <- par.div.dep[5]
transition_from_trait_2_to_1 <- par.div.dep[6]
transition_rate_ratio_1to2_over_2to1 <- transition_from_trait_1_to_2/transition_from_trait_2_to_1
      

## Crown age per trait AUC and effect size
tip.length <- this_tree$edge.length[this_tree$edge[, 2] %in% 1:Ntip(this_tree)]
tip.length <- (tip.length - min(tip.length)) / (max(tip.length) - min(tip.length))
this_trait <- this_world[match(this_tree$tip.label, this_world[, 8]), 6]
tip.length.2 <- tip.length[this_trait == 2]
tip.length.1 <- tip.length[this_trait == 1]
model <- glm(as.factor(this_trait) ~ log(tip.length + 1),
             family = "binomial")
effect.size <- model$coefficients[2]
# plot(y = this_trait - 1, x= log(tip.length))
p <- predict(model, as.factor(this_trait), type = "resp")
# points(y = p, x = log(tip.length), col = "red")
pr <- prediction(p, as.factor(this_trait))
auc.model <- performance(pr, measure = "auc")@y.values[[1]]
## Phylogenetic signal (D)
Phylogenetic_signal <- Dsig(mytree = this_tree, myWorld = this_world)

Spatial Locations


## Spatial Analysis
nbs0 <- knearneigh(as.matrix(this_world[, 2:3]), k = 7, longlat = TRUE)
nbs <- knn2nb(nbs0, sym = TRUE) # 7 symmetric neighbors
nbs.listw <- nb2listw(nbs)
factors.nbs <- as.factor(ifelse(is.na(this_world[, 6]), 3, this_world[, 6]))
spatial.tests <- joincount.test(fx = factors.nbs, listw = nbs.listw)
spatial.tests.fora <- spatial.tests[[1]]$statistic
spatial.tests.dom <- spatial.tests[[2]]$statistic
#prevalence <- (N.for.dom[1] - N.for.dom[2]) / sum(N.for.dom)
results_summary_matrix_1 <- cbind(

        number_of_branches,
        #Pylo_diversity_is_sum_of_BL,
        #average_phylogenetic_diversity_is_mean_of_BL,
        #variance_Pylo_diversity_is_variance_of_BL,

        F_quadratic_entropy_is_sum_of_PD,
        Mean_pairwise_distance,
        variance_pairwise_distance,

        #Evolutionary_distinctiveness_sum,
        #mean_Phylogenetic_isolation,
        #variance_Phylogenetic_isolation,

        gamma,
        gamma_p_value,
        speciation_rate,
        extinction_rate,
        extinction_per_speciation,
        speciation_minus_extinction,
        trait_1_speciation,
        trait_2_speciation ,
        trait_1_extinction ,
        trait_2_extinction ,
        transition_from_trait_1_to_2 ,
        transition_from_trait_2_to_1 ,
        transition_rate_ratio_1to2_over_2to1 ,
        Phylogenetic_signal,
        spatial.tests.fora,
        spatial.tests.dom,
       # prevalence,
       # auc.model,
        effect.size
      )
      #rownames(results_summary_matrix_1) <- 1

      #results_summary_matrix_2 <- cbind(
      #  c(Evolutionary_distinctiveness,NA),
      #  lineages_through_time,
      #  time_steps
      #)
      #colnames(results_summary_matrix_2) <- c("Evolutionary_distinctiveness", "lineages_through_time", "time_steps")
      #head(results_summary_matrix_2)

      ### Returns from function in list form
      #returns <- list(
        #Branch_Lengths,
        #Pairwise_dist,
      #  results_summary_matrix_1,
      #  results_summary_matrix_2

      #)

      #names(returns) <- c(
        #"Branch_Lengths",
        #"Pairwise_distance",
       # "results_summary_of_single_value_outputs",
       # "results_summary_matrix_of_multi_value_outputs"
      #)
      
      

Module2() returns these two matrices as a list

Here is the exact version in R

## This module analyzes the results from module 1 and returns a list based on how many values each stat returns
## Ty Tuff and Bruno Vilela
## 24 August 2016

###### Specify function ##############################

Module_2 <- function(Module_1_output) {
  cat("\nAnalyzing: 0% [")
  if (any(is.na(Module_1_output))) {
    cat("----------]")
    return(NA)
  } else {

    this_tree <- Module_1_output$mytree
    this_world <- Module_1_output$myWorld

    ##### (0) Pull necessary variables from simulated trees and organize into a single object for all the tests below to pull from.

    #str(all_trees)
    #str(this_tree)

    ## 0a) Branch lengths
    Branch_Lengths <- this_tree$edge.length
    number_of_branches <- length(Branch_Lengths)

    # Anchor test = PD (Faith's phylogenetic diversity)
    Pylo_diversity_is_sum_of_BL <- sum(Branch_Lengths)

    # avPD -- Average phylogenetic diversity
    average_phylogenetic_diversity_is_mean_of_BL <- mean(Branch_Lengths)

    variance_Pylo_diversity_is_variance_of_BL <- var(Branch_Lengths)
    cat("-")
    ## 0b) Pairwise distance between tips
    Pairwise_dist <- cophenetic.phylo(this_tree)
    cat("-")
    # 2b) Pairwise distance -- Sum of pairwise distances

    # F -- Extensive quadratic entropy
    F_quadratic_entropy_is_sum_of_PD <- sum(Pairwise_dist)

    #Mean inter-species distances

    # Anchor test = MPD (mean pairwise distance)

    Mean_pairwise_distance <- mean(Pairwise_dist)

    cat("-")
    #Pairwise distance/all distances -- Variance of pairwise distances

    # Anchor test = VPD (variation of pairwise distance)

    variance_pairwise_distance <- var(as.vector(Pairwise_dist))

    ## 0c) Phylogenetic isolation

    # Using equal.splits method, faster computation
    Evolutionary_distinctiveness <- evol.distinct2(this_tree, type = "fair.proportion")
    cat("-")
    # ED - Summed evolutionary distinctiveness

    Evolutionary_distinctiveness_sum <- sum(Evolutionary_distinctiveness)

    ## 3d) Phylogenetic isolation -- Mean of species evolutionary distinctiveness

    # mean(ED)

    mean_Phylogenetic_isolation <- mean(Evolutionary_distinctiveness)

    ## 4d) Phylogenetic isolation -- Variance of species isolation metrics

    #var(ED)

    variance_Phylogenetic_isolation <- var(Evolutionary_distinctiveness)
    cat("-")

    ## Tree topology

    #Gamma index

    ltts <- ltt(this_tree, gamma = TRUE, plot = FALSE)
    lineages_through_time <- as.numeric(ltts[[1]])
    time_steps <- as.numeric(ltts[[2]])
    gamma <- ltts[[3]]
    gamma_p_value <- ltts[[4]]
    cat("-")

    colless_stat <- colless(as.treeshape(this_tree))
    sackin_index <- sackin(as.treeshape(this_tree))
    tree_shape_stat <- shape.statistic(as.treeshape(this_tree))

    ##### (5) Tree metric -- Macroevolutionary - Rate and rate changes ###############
    ##################################################

    ## Speciation vs extinction rates and Net diversification
    bds <- bd(this_tree)
    speciation_rate <- bds[1]
    extinction_rate <- bds[2]
    extinction_per_speciation <- bds[3]
    speciation_minus_extinction <- bds[4]
    cat("-")

    ## Speciation vs extinction rates and Net diversification dependent on trait
    N.for.dom <- table(this_world[, 6])
    if(length(N.for.dom) == 2) {
      par.div.dep <- DivDep( mytree = this_tree, myWorld = this_world)
      trait_1_speciation <- par.div.dep[1]
      trait_2_speciation <- par.div.dep[2]
      trait_1_extinction <- par.div.dep[3]
      trait_2_extinction <- par.div.dep[4]
      transition_from_trait_1_to_2 <- par.div.dep[5]
      transition_from_trait_2_to_1 <- par.div.dep[6]
      transition_rate_ratio_1to2_over_2to1 <- transition_from_trait_1_to_2/transition_from_trait_2_to_1
      cat("-")

      ## Phylogenetic signal (D)
      Phylogenetic_signal <- Dsig(mytree = this_tree, myWorld = this_world)
      cat("-")

      ## Spatial Analysis
      nbs0 <- knearneigh(as.matrix(this_world[, 2:3]), k = 7, longlat = TRUE)
      nbs <- knn2nb(nbs0, sym = TRUE) # 7 symmetric neighbors
      nbs.listw <- nb2listw(nbs)
      factors.nbs <- as.factor(ifelse(is.na(this_world[, 6]), 3, this_world[, 6]))
      spatial.tests <- joincount.test(fx = factors.nbs, listw = nbs.listw)
      spatial.tests.fora <- spatial.tests[[1]]$statistic
      spatial.tests.dom <- spatial.tests[[2]]$statistic
      prevalence <- (N.for.dom[1] - N.for.dom[2]) / sum(N.for.dom)
      cat("-")
    } else {
      trait_1_speciation <- NA
      trait_2_speciation <- NA
      trait_1_extinction <- NA
      trait_2_extinction <- NA
      transition_from_trait_1_to_2 <- NA
      transition_from_trait_2_to_1 <- NA
      transition_rate_ratio_1to2_over_2to1 <- NA
      Phylogenetic_signal <- NA
      spatial.tests.fora <- NA
      spatial.tests.dom <- NA
      prevalence <- ifelse(names(table(this_world[, 6])[1]) == "1", 1,
                           -1)
      cat("---")

    }

    results_summary_matrix_1 <- cbind(

      number_of_branches,
      Pylo_diversity_is_sum_of_BL,
      average_phylogenetic_diversity_is_mean_of_BL,
      variance_Pylo_diversity_is_variance_of_BL,

      F_quadratic_entropy_is_sum_of_PD,
      Mean_pairwise_distance,
      variance_pairwise_distance,

      colless_stat ,
      sackin_index ,
      tree_shape_stat,

      Evolutionary_distinctiveness_sum,
      mean_Phylogenetic_isolation,
      variance_Phylogenetic_isolation,

      gamma,
      gamma_p_value,
      speciation_rate,
      extinction_rate,
      extinction_per_speciation,
      speciation_minus_extinction,
      trait_1_speciation,
      trait_2_speciation ,
      trait_1_extinction ,
      trait_2_extinction ,
      transition_from_trait_1_to_2 ,
      transition_from_trait_2_to_1 ,
      transition_rate_ratio_1to2_over_2to1 ,
      Phylogenetic_signal,
      spatial.tests.fora,
      spatial.tests.dom,
      prevalence
    )
    rownames(results_summary_matrix_1) <- 1

    results_summary_matrix_2 <- cbind(
      c(Evolutionary_distinctiveness,NA),
      lineages_through_time,
      time_steps
    )
    colnames(results_summary_matrix_2) <- c("Evolutionary_distinctiveness",
                                            "lineages_through_time", "time_steps")
    head(results_summary_matrix_2)

    ### Returns from function in list form
    returns <- list(
      #Branch_Lengths,
      #Pairwise_dist,
      results_summary_matrix_1,
      results_summary_matrix_2

    )

    names(returns) <- c(
      #"Branch_Lengths",
      #"Pairwise_distance",
      "results_summary_of_single_value_outputs",
      "results_summary_matrix_of_multi_value_outputs"
    )
    cat("] 100%")

    return(returns)

  }
}


#Module_2(myOut)

References

setwd("~/Box Sync/colliding ranges/Simulations_humans/Results/RF_daily_output")

details <- file.info(list.files())

trimmed_details <- details[which(list.files() == list.files(pattern = "Four_model_compare_results_extinct*")),]
ord <- order(trimmed_details$mtime, decreasing = TRUE)
rownames(trimmed_details[ord,])[1]
load(rownames(trimmed_details[ord,])[1])
extinct <- Concatenated_data
str(fit)
fit$confusion
as.vector(fit$confusion)
as.vector(fit$test$confusion)
fit$importance[,5]
fit$importanceSD[,5]


str(fit)
fit$confusion
plot(fit$err.rate[,1])
lines(fit$err.rate[,2])
lines(fit$err.rate[,3])
lines(fit$err.rate[,4])
lines(fit$err.rate[,5])
library(png)
## First consolidate the available files into a single table
    
      path <- "~/Box Sync/Four model compare/Module 2"
           
     
           setwd(path)
    myfiles_full <- list.dirs()
    analyze_this_many <- length(myfiles_full)
    
    available_files <- matrix(NA, 1, 1)
    
        
    for(i in 1: analyze_this_many){
    available_files <- rbind(available_files , as.matrix(list.files(myfiles_full[i], full.names = TRUE)))
    }
    dim(available_files)
    
    split.file.name <- strsplit(available_files[10], split = "_") 
    
    
    
 
available <- list.files()
files <- matrix(rep(NA, 62), length(available), 62)
dim(files)
i <- 10


for(i in 1:length(available)){
load(available[i])
name <- unlist(strsplit(available[i], split="_"))
files[i,] <- c(as.vector(matrix(name, 1,35)),matrix(Sim_statistics[[1]], 1, 27))

}


colnames(files) <-  c(

    NA,
    "background_takeover_type" ,
    NA,
    "replicate",
    NA,
    "Model_type",
    rep(NA,2),
    "speciation_of_Env_NonD",
    "speciation_of_Env_D",
    "speciation_of_For",
    "speciation_of_Dom",
    NA,
    "extinction_of_Env_NonD",
    "extinction_of_Env_D",
    "extinction_of_For",
    "extinction_of_Dom",
    NA,
    "P.diffusion_Target_forager",
    "P.diffusion_Target_domesticator",
    "P.diffusion_Source_forager",
    "P.diffusion_Source_domesticator",
    NA,
    "P.takeover_Target_forager",
    "P.takeover_Target_domesticator",
    "P.takeover_Source_forager",
    "P.takeover_Source_domesticator",
    NA,
    "arisal_of_Env_NonD",
    "arisal_of_Env_D",
    "arisal_of_For",
    "arisal_of_Dom",
    
    NA, 
    "timesteps", 
    NA,
        
    "number_of_branches",
    "Pylo_diversity_is_sum_of_BL",
    "average_phylogenetic_diversity_is_mean_of_BL",
    "variance_Pylo_diversity_is_variance_of_BL",

    "F_quadratic_entropy_is_sum_of_PD",
    "Mean_pairwise_distance",
    "variance_pairwise_distance",

    "Evolutionary_distinctiveness_sum",
    "mean_Phylogenetic_isolation",
    "variance_Phylogenetic_isolation",

    "gamma",
    "gamma_p_value",
    "speciation_rate",
    "extinction_rate",
    "extinction_per_speciation",
    "speciation_minus_extinction",
    "trait_1_speciation",
    "trait_2_speciation" ,
    "trait_1_extinction" ,
    "trait_2_extinction" ,
    "transition_from_trait_1_to_2" ,
    "transition_from_trait_2_to_1" ,
    "transition_rate_ratio_1to2_over_2to1" ,
    "Phylogenetic_signal",
    "spatial.tests.fora",
    "spatial.tests.dom",
    "prevalence"
    
    
  )

results_table <- as.data.frame(files)
head(results_table)
dim(results_table)
Concatenated_data <- results_table
save(Concatenated_data, file="~/Desktop/Four_model_compare_results.Rdata")

one <- subset(results_table, Model_type=="01" )
two <- subset(results_table, Model_type=="02" )
three <- subset(results_table, Model_type=="03" )
four <- subset(results_table, Model_type=="04" )
crop <- min(length(one[,1]),
length(two[,1]),
length(three[,1]),
length(four[,1]))
one <- one[1:crop,]
two <- two[1:crop,]
three <- three[1:crop,]
four <- four[1:crop,]

Concatenated_data <- rbind(one, two, three, four)
dim(Concatenated_data)





save(Concatenated_data, file=paste0("~/Box Sync/colliding ranges/Simulations_humans/Results/available daily summaries/Four_model_compare_results", format(Sys.time(), format="%d_%b_%Y"),"_crop_to_", crop,".Rdata"))
crop
## First consolidate the available files into a single table
    
      path <- "~/Box Sync/Four model compare/Module 2 extinct"
           
     
           setwd(path)
    myfiles_full <- list.dirs()
    analyze_this_many <- length(myfiles_full)
    
    available_files <- matrix(NA, 1, 1)
    
        
    for(i in 1: analyze_this_many){
    available_files <- rbind(available_files , as.matrix(list.files(myfiles_full[i], full.names = TRUE)))
    }
    dim(available_files)
    
    split.file.name <- strsplit(available_files[10], split = "_") 
    
    
    
 
available <- list.files()
files <- matrix(rep(NA, 62), length(available), 62)
dim(files)
i <- 10


for(i in 1:length(available)){
load(available[i])
name <- unlist(strsplit(available[i], split="_"))
files[i,] <- c(as.vector(matrix(name, 1,35)),matrix(Sim_statistics[[1]], 1, 27))

}


colnames(files) <-  c(

    NA,
    "background_takeover_type" ,
    NA,
    "replicate",
    NA,
    "Model_type",
    rep(NA,2),
    "speciation_of_Env_NonD",
    "speciation_of_Env_D",
    "speciation_of_For",
    "speciation_of_Dom",
    NA,
    "extinction_of_Env_NonD",
    "extinction_of_Env_D",
    "extinction_of_For",
    "extinction_of_Dom",
    NA,
    "P.diffusion_Target_forager",
    "P.diffusion_Target_domesticator",
    "P.diffusion_Source_forager",
    "P.diffusion_Source_domesticator",
    NA,
    "P.takeover_Target_forager",
    "P.takeover_Target_domesticator",
    "P.takeover_Source_forager",
    "P.takeover_Source_domesticator",
    NA,
    "arisal_of_Env_NonD",
    "arisal_of_Env_D",
    "arisal_of_For",
    "arisal_of_Dom",
    
    NA, 
    "timesteps", 
    NA,
        
    "number_of_branches",
    "Pylo_diversity_is_sum_of_BL",
    "average_phylogenetic_diversity_is_mean_of_BL",
    "variance_Pylo_diversity_is_variance_of_BL",

    "F_quadratic_entropy_is_sum_of_PD",
    "Mean_pairwise_distance",
    "variance_pairwise_distance",

    "Evolutionary_distinctiveness_sum",
    "mean_Phylogenetic_isolation",
    "variance_Phylogenetic_isolation",

    "gamma",
    "gamma_p_value",
    "speciation_rate",
    "extinction_rate",
    "extinction_per_speciation",
    "speciation_minus_extinction",
    "trait_1_speciation",
    "trait_2_speciation" ,
    "trait_1_extinction" ,
    "trait_2_extinction" ,
    "transition_from_trait_1_to_2" ,
    "transition_from_trait_2_to_1" ,
    "transition_rate_ratio_1to2_over_2to1" ,
    "Phylogenetic_signal",
    "spatial.tests.fora",
    "spatial.tests.dom",
    "prevalence"
    
    
  )

Concatenated_data <- as.data.frame(files)
head(Concatenated_data)
dim(Concatenated_data)

save(Concatenated_data, file=paste0("~/Box Sync/colliding ranges/Simulations_humans/Results/available daily summaries/Four_model_compare_results_extinct_", format(Sys.time(), format="%d_%b_%Y"),"_crop_to_", crop,".Rdata"))
load('~/Box Sync/colliding ranges/Simulations_humans/Results/available daily summaries/Four_model_compare_results_02_Mar_2017_crop_to_3481.Rdata')
extant <- Concatenated_data
extant
setwd("~/Box Sync/colliding ranges/Simulations_humans/Results/available daily summaries")
details <- file.info(list.files())

trimmed_details <- details[which(list.files() == list.files(pattern = "Four_model_compare_results_extinct*")),]
ord <- order(trimmed_details$mtime, decreasing = TRUE)
rownames(trimmed_details[ord,])[1]
load(rownames(trimmed_details[ord,])[1])
extinct <- Concatenated_data

trimmed_details <- details[which(list.files() != list.files(pattern = "Four_model_compare_results_extinct*")),]
ord <- order(trimmed_details$mtime, decreasing = TRUE)
rownames(trimmed_details[ord,])[1]
load(rownames(trimmed_details[ord,])[1])
extant <- Concatenated_data
dim(extinct)
dim(extant)

for(i in c(9,10,11,12,14,15,16,17,19,20,21,22,24,25,26,27,29,30,31,32)){
    extinct[which(is.nan(as.numeric(as.character(extinct[, i]))) == TRUE), i] <- NA
}

for(i in c(9,10,11,12,14,15,16,17,19,20,21,22,24,25,26,27,29,30,31,32)){
    extant[which(is.nan(as.numeric(as.character(extant[, i]))) == TRUE), i] <- NA
}

i <- 19
for(i in c(20,21,24,25,26,27)){
    extinct[which(as.numeric(as.character(extinct[, i])) == 0), i] <- NA
}

for(i in c(20,21,24,25,26,27)){
    extant[which(as.numeric(as.character(extant[, i])) == 0), i] <- NA
}


xlimit <- c(0,1)
ylimit <- c(0,600)
maincex <- 0.9

png(file="Global_success_rate_per_parameter.png", width=8.5, height=11, units="in", res=300)

par(mfrow=c(5,4), mar=c(3,3,3,0))


hist(as.numeric(as.character(extinct[,9])), main="speciation of F in F env", col=adjustcolor("firebrick", alpha=0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[,9])), main="speciation of F in F env", col=adjustcolor("cornflowerblue", alpha=0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)


hist(as.numeric(as.character(extinct[,10])), main="speciation of D in F env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[,10])), main="speciation of D in F env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)


hist(as.numeric(as.character(extinct[,11])), main="speciation of F in D env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[,11])), main="speciation of F in D env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[,12])), main="speciation of D in D env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[,12])), main="speciation of D in D env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

#######

hist(as.numeric(as.character(extinct[, 14])), main="extinction of F in F env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 14])), main="extinction of F in F env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)



hist(as.numeric(as.character(extinct[, 15])), main="extinction of D in F env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 15])), main="extinction of D in F env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 16])), main="extinction of F in D env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 16])), main="extinction of F in D env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 17])), main="extinction of D in D env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 17])), main="extinction of D in D env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

######

hist(as.numeric(as.character(extinct[, 29])), main="arisal of F in F env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 29])), main="arisal of F in F env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)



hist(as.numeric(as.character(extinct[, 30])), main="arisal of D in F env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 30])), main="arisal of D in F env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 31])), main="arisal of F in D env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 31])), main="arisal of F in D env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 32])), main="arisal of D in D env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 32])), main="arisal of D in D env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

######

hist(as.numeric(as.character(extinct[, 19])), main="NOPE -- Diffusion: source F, target F", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= c(0,18000), cex.main= maincex)
hist(as.numeric(as.character(extant[, 19])), main="NOPE -- Diffusion: source F, target F", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= c(0,18000), cex.main= maincex, add=TRUE)



hist(as.numeric(as.character(extinct[, 20])), main="Diffusion: source D, target F", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 20])), main="Diffusion: source D, target F", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 21])), main="Diffusion: source F, target D", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 21])), main="Diffusion: source F, target D", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 22])), main="NOPE -- Diffusion: source D, target D", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= c(0,18000), cex.main= maincex)
hist(as.numeric(as.character(extant[, 22])), main="NOPE -- Diffusion: source D, target D", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= c(0,18000), cex.main= maincex, add=TRUE)

####

hist(as.numeric(as.character(extinct[, 24])), main="Takeover: source F, target F", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 24])), main="Takeover: source F, target F", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)



hist(as.numeric(as.character(extinct[, 25])), main="Takeover: source D, target F", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 25])), main="Takeover: source D, target F", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 26])), main="Takeover: source F, target D", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 26])), main="Takeover: source F, target D", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 27])), main="Takeover: source D, target D", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 27])), main="Takeover: source D, target D", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)


dev.off()



png(file="extiction minus extant per outcome.png", width=8.5, height=11, units="in", res=300)
par(mfrow=c(3,1))

plot(as.numeric(as.character(extinct[,9])), as.numeric(as.character(extinct[,14])), xlab="speciation", ylab="extinction", col= adjustcolor("firebrick", alpha=0.2), pch=19, cex=0.6, ylim=c(0,1))
plot(as.numeric(as.character(extant[,9])), as.numeric(as.character(extant[,14])), xlab="speciation", ylab="extinction", col= adjustcolor("cornflowerblue", alpha=0.2), pch=19, cex=0.6, ylim=c(0,1))

plot(as.numeric(as.character(extinct[,9])), as.numeric(as.character(extinct[,14])), xlab="speciation", ylab="extinction", col= adjustcolor("firebrick", alpha=0.2), pch=19, cex=0.6, ylim=c(0,1))
points(as.numeric(as.character(extant[,9])), as.numeric(as.character(extant[,14])), xlab="speciation", ylab="extinction", col= adjustcolor("cornflowerblue", alpha=0.2), pch=19, cex=0.6)


dev.off()

params <- extant[,-1:-35]
names(params)
break_number <- 10
xmin <-
xmax <- 

x1 <- as.numeric(params[,1])
h1 <- hist(x1,  plot=FALSE, breaks= break_number)
xfit1 <- seq(xmin, xmax, length= 100)
yfit1 <- dnorm(xfit1, mean=mean(x1), sd=sd(x1))
yfit1 <- yfit1*diff(h1$mids[1:2])*length(x1)+101.5
polygon(xfit1, yfit1, col=adjustcolor("limegreen", alpha=0.5), lwd=2, border=adjustcolor("limegreen", alpha=0.6))

setwd("~/Box Sync/colliding ranges/Simulations_humans/Results/available daily summaries")
details <- file.info(list.files())

trimmed_details <- details[which(list.files() == list.files(pattern = "Four_model_compare_results_extinct*")),]
ord <- order(trimmed_details$mtime, decreasing = TRUE)
rownames(trimmed_details[ord,])[1]
load(rownames(trimmed_details[ord,])[1])
extinct <- Concatenated_data

trimmed_details <- details[which(list.files() != list.files(pattern = "Four_model_compare_results_extinct*")),]
ord <- order(trimmed_details$mtime, decreasing = TRUE)
rownames(trimmed_details[ord,])[1]
load(rownames(trimmed_details[ord,])[1])
extant <- Concatenated_data



load('~/Box Sync/colliding ranges/Simulations_humans/Available trees/real.analysis.RData')

Concatenated_data <- extant
head(Concatenated_data)
#Concatenated_data <- Concatenated_data[Concatenated_data[, 2] == "stats.no.bTO", ]
#Concatenated_data <- Concatenated_data[Concatenated_data[, 6] != "05", ]
# Concatenated_data[, 6] <- as.numeric(Concatenated_data[, 6])
# # Concatenated_data[original[, 2] == "background_takeover", 6] <-  Concatenated_data[original[, 2] == "background_takeover", 6] + 4
Concatenated_data[, 6] <- factor(Concatenated_data[, 6])
#head(Concatenated_data)
#names(Concatenated_data)

PCAdata <- Concatenated_data[, -(1:35)]
PCAdata <- PCAdata[, -12]
PCAdata <- apply(PCAdata, 2, as.numeric)
remove <- apply(is.na(PCAdata), 1, any)
PCAdata <- PCAdata[!remove, ]

# Predictions
library(randomForest)

data.analysis.comp2 <- data.frame("Model" = as.factor(Concatenated_data[!remove, 6]),
                                  PCAdata)
data.analysis.comp2$sprate <- data.analysis.comp2$trait_1_speciation/data.analysis.comp2$trait_2_speciation
data.analysis.comp2$extrate <- data.analysis.comp2$trait_1_extinction/data.analysis.comp2$trait_2_extinction


#load("Real_phy/real.analysis.RData")
a <- as.data.frame(real.analysis$results_summary_of_single_value_outputs)
a$sprate <- a$trait_1_speciation / a$trait_2_speciation
a$extrate <- a$trait_1_extinction / a$trait_2_extinction

data.analysis.comp3 <- data.analysis.comp2[, -c(2, 13:14, 16:20)]
#data.analysis.comp3 <- data.analysis.comp3[data.analysis.comp3$Model %in% 1:4, ]
#data.analysis.comp3$Model <- factor(data.analysis.comp3$Model)
#sub <- unlist(lapply(as.list(c(1:4)), function(x, y) {
#  sample(which(y$Model == x), min(table(data.analysis.comp3$Model)))},
#  y = data.analysis.comp3))
# data.analysis.comp3 <- data.analysis.comp3[sub, ]
fun <- function(x, y, per = .33) {sample(which(y$Model == x), round(table(y$Model)[1]*per))}

sub.test <- unlist(lapply(as.list(paste0(0, c(1:4))), fun,
                          y = data.analysis.comp3))
test2 <- data.analysis.comp3[sub.test, 2:ncol(data.analysis.comp3)]
test1 <- data.analysis.comp3[sub.test, 1]
train <- data.analysis.comp3[-sub.test, ]

train[, -1] <- apply(train[, -1], 2, as.numeric)
test2 <- as.data.frame(apply(test2, 2, as.numeric))
infinites <- which(apply(train[, -1], 2, is.infinite), arr.ind=T)
if (nrow(infinites) > 0) {
train <- train[-infinites[, 1], ]
}
infinites2 <- which(apply(test2, 2, is.infinite), arr.ind=T)
if (nrow(infinites2) > 0) {
test2 <- test2[-infinites2[, 1], ]
test1 <- test1[-infinites2[, 1]]
}


for(i in 1:100){
(fit <- randomForest(Model ~ ., data=train, xtest = test2, ytest = test1, 
                    importance=TRUE, ntree=1000, keep.forest = TRUE, replace=FALSE))

predictions <- predict(fit, 
                       a,
                       type="prob")
predictions

save(fit, file=paste0("~/Box Sync/colliding ranges/Simulations_humans/Results/RF_daily_output/RF_daily_output_", format(Sys.time(), format="%d_%b_%Y"), "_",i, "_NoREPLACEMENT_.Rdata"))
}


save(fit, file=paste0("~/Box Sync/colliding ranges/Simulations_humans/Results/RF_daily_output/RF_daily_output_", format(Sys.time(), format="%d_%b_%Y"),".Rdata"))

plot(fit, ylim=c(0,1))
labs <- c("Basic", "+Diffusion", "+Takeover", "+Diffusion +Takeover")
# bar plot
png("Prob_aus.png", width = 25, height = 25, res = 300, units = "in")
par(mar = c(8, 8, 1, 1))
pred <- setNames(as.numeric(predictions), labs)
cols <- rev(c("darkgreen", "red", "blue", "darkorange1"))
barplot(pred, col = cols, ylab = "Proability", cex.lab = 3, cex.names = 2)
dev.off()
# Plot confusion matrix
png("Conffusion_matrix_all.png", width = 25, height = 25, res=300, units="in")
par(mar = c(10, 11, 1, 1))
colors1 <- colorRampPalette(colors = c("#f0f0f0", "#bdbdbd","#636363"))
prop <- apply(fit$confusion[, -5], 2, function(x){x / sum(x)}) * 100

image(prop, col = colors1(20), axes=FALSE)
axis(1, at=c(0, .33, .66, 1), labels=labs, tick = FALSE, line = FALSE, cex.axis = 3.5, pos = -.19)
axis(2, at=c(0, .33, .66, 1), labels=labs, tick = FALSE, line = FALSE, cex.axis = 3.5)
mtext("ACTUAL", side = 1, padj = 3, cex = 4)
mtext("PREDICTED", side = 2, padj = -3, cex = 4)

for(i in 1:4) {
  for(j in 1:4) {
    text(x = c(0, .33, .66, 1)[i], y = c(0, .33, .66, 1)[j], paste0(round(prop[i, j], 2), "%"),
         cex = 5)
  }
}
dev.off()
importance(fit)
# Variables importance

imp <- importance(fit)
imp <- apply(imp, 2, function(x) (x - min(x))/(max(x) - min(x)))
imp <- imp[sort(imp[, 5], index.return = TRUE, decreasing = TRUE)$ix, ]


names <- rownames(imp)
names[names == "spatial.tests.fora"] <- "Space F"
names[names == "spatial.tests.dom"] <- "Space D"
names[names == "sprate"] <- "Sp(ratio)"
names[names == "transition_from_trait_1_to_2"] <- "TR(1-2)"
names[names == "transition_from_trait_2_to_1"] <- "TR(2-1)"
names[names == "Phylogenetic_signal"] <- "PhySig(D)"
names[names == "Evolutionary_distinctiveness_sum"] <- "EDsum"
names[names == "Pylo_diversity_is_sum_of_BL"] <- "PDsum"
names[names == "transition_rate_ratio_1to2_over_2to1"] <- "TR(ratio)"
names[names == "gamma"] <- "Gamma"
names[names == "mean_Phylogenetic_isolation"] <- "MPI"
names[names == "extrate"] <- "Ext(ratio)"
names[names == "average_phylogenetic_diversity_is_mean_of_BL"] <- "PDmean"
names[names == "extinction_per_speciation"] <- "DR"
names[names == "variance_Phylogenetic_isolation"] <- "VPI"
names[names == "F_quadratic_entropy_is_sum_of_PD"] <- "F"
names[names == "Mean_pairwise_distance"] <- "MPD"
names[names == "variance_Pylo_diversity_is_variance_of_BL"] <- "PDvar"
names[names == "variance_pairwise_distance"] <- "VPD"


png("var_import_all.png", width = 25, height = 25, unit="in", res=300)
par(mar = c(10, 18, 1, 1))
plot(x = rev(imp[, 5]), y = 1:nrow(imp), type = "l", yaxt = "n", 
     ylab = "", xlab = "Variable Importance",
     xlim = c(0, 1), lwd = 2, cex.lab = 4)
for (i in 1:nrow(imp)) {
  abline(h = i, lty = 3, col = "gray80")
}
abline(v = seq(0, 1, 1/19), lty = 3, col = "gray80")

lines(x = rev(imp[, 4]), y = 1:nrow(imp), col = "darkgreen", lwd = 2)
lines(x = rev(imp[, 3]), y = 1:nrow(imp), col = "red", lwd = 2)
lines(x = rev(imp[, 2]), y = 1:nrow(imp), col = "blue", lwd = 2)
lines(x = rev(imp[, 1]), y = 1:nrow(imp), col = "darkorange1", lwd = 2)
lines(x = rev(imp[, 5]), y = 1:nrow(imp), lwd = 3)

points(x = rev(imp[, 4]), y = 1:nrow(imp), col = "darkgreen", cex = 2)
points(x = rev(imp[, 3]), y = 1:nrow(imp), col = "red", cex = 2)
points(x = rev(imp[, 2]), y = 1:nrow(imp), col = "blue", cex = 2)
points(x = rev(imp[, 1]), y = 1:nrow(imp), col = "darkorange1", cex = 2)
points(x = rev(imp[, 5]), y = 1:nrow(imp), pch = 20, cex = 3)


text(y = 1:nrow(imp), x = par("usr")[1] - .17, labels = rev(names),
     srt = 0, pos = 4, xpd = T, cex = 4)
dev.off()
par(mfrow=c(2,3))

# Box plots
boxplot(spatial.tests.fora ~ Model, data = data.analysis.comp3)
abline(h = a$spatial.tests.fora, col = "red", lty = 2)

boxplot(spatial.tests.dom ~ Model, data = data.analysis.comp3)
abline(h = a$spatial.tests.fora, col = "red", lty = 2)

boxplot(log(sprate) ~ Model, data = data.analysis.comp3, ylim = c(-10, 10))
abline(h = log(a$sprate), col = "red", lty = 2)

boxplot(log(extrate) ~ Model, data = data.analysis.comp3, ylim = c(-10, 10))
abline(h = log(a$extrate), col = "red", lty = 2)

boxplot(log(transition_rate_ratio_1to2_over_2to1) ~ Model, data = data.analysis.comp3)
abline(h = log(a$sprate), col = "red", lty = 2)

boxplot(Phylogenetic_signal ~ Model, data = data.analysis.comp3, ylim = c(0, 1))
abline(h = a$Phylogenetic_signal, col = "red", lty = 2)
#build a data tracking table to track parameter changes through time

str(fit)

y
setwd("~/Box Sync/colliding ranges/Simulations_humans/Results/RF_daily_output")

details <- file.info(list.files())

trimmed_details <- details[which(list.files() == list.files(pattern = "Four_model_compare_results_extinct*")),]
ord <- order(trimmed_details$mtime, decreasing = TRUE)
rownames(trimmed_details[ord,])[1]
load(rownames(trimmed_details[ord,])[1])
extinct <- Concatenated_data
str(fit)
fit$confusion
as.vector(fit$confusion)
as.vector(fit$test$confusion)
fit$importance[,5]
fit$importanceSD[,5]


str(fit)
fit$confusion
plot(fit$err.rate[,1])
lines(fit$err.rate[,2])
lines(fit$err.rate[,3])
lines(fit$err.rate[,4])
lines(fit$err.rate[,5])
load('~/Downloads/FULL_TREE_Society_data_with_binary_conversions.Rdata')

load('~/Downloads/Tree_FULL_trimmed.Rdata')

this_tree <- full_tree 


load('~/Downloads/download.Rdata')
objects()
str(myOut)

this_tree <- myOut$mytree
this_world <- myOut$myWorld

R Markdown

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

When you click the Knit button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:


stop <- function(){


library(ape)
library(phytools)
library(diversitree)
library(spdep)
library(Rcpp)
library(msm)
library(FARM)
options(repos = c(CRAN = "http://cran.rstudio.com"))
install.packages("devtools")
library(devtools)
install_github("BrunoVilela/FARM")
library(FARM)

load('~/Downloads/FULL_TREE_Society_data_with_binary_conversions.Rdata')

load('~/Downloads/Tree_FULL_trimmed.Rdata')

this_tree <- full_tree 


load('~/Downloads/download.Rdata')
objects()
str(myOut)


this_world <- myOut$myWorld

## This module analyzes the results from module 1 and returns a list based on how many values each stat returns
## Ty Tuff and Bruno Vilela
## 24 August 2016

###### Specify function ##############################

    #  this_tree <- Module_1_output$mytree
    #  this_world <- Module_1_output$myWorld

      ##### (0) Pull necessary variables from simulated trees and organize into a single object for all the tests below to pull from.

      #str(all_trees)
      #str(this_tree)

      ## 0a) Branch lengths
      Branch_Lengths <- this_tree$edge.length
      number_of_branches <- length(Branch_Lengths)

      # Anchor test = PD (Faith's phylogenetic diversity)
      Pylo_diversity_is_sum_of_BL <- sum(Branch_Lengths)

      # avPD -- Average phylogenetic diversity
      average_phylogenetic_diversity_is_mean_of_BL <- mean(Branch_Lengths)

      variance_Pylo_diversity_is_variance_of_BL <- var(Branch_Lengths)
      cat("-")
      ## 0b) Pairwise distance between tips
      Pairwise_dist <- cophenetic(this_tree)
      cat("-")
      # 2b) Pairwise distance -- Sum of pairwise distances

      # F -- Extensive quadratic entropy
      F_quadratic_entropy_is_sum_of_PD <- sum(Pairwise_dist)

      #Mean inter-species distances

      # Anchor test = MPD (mean pairwise distance)

      Mean_pairwise_distance <- mean(Pairwise_dist)

      cat("-")
      #Pairwise distance/all distances -- Variance of pairwise distances

      # Anchor test = VPD (variation of pairwise distance)

      variance_pairwise_distance <- var(as.vector(Pairwise_dist))

      ## 0c) Phylogenetic isolation

      # Using equal.splits method, faster computation
      Evolutionary_distinctiveness <- evol.distinct2(this_tree, type = "equal.splits")
      cat("-")
      # ED - Summed evolutionary distinctiveness

      Evolutionary_distinctiveness_sum <- sum(Evolutionary_distinctiveness)

      ## 3d) Phylogenetic isolation -- Mean of species evolutionary distinctiveness

      # mean(ED)

      mean_Phylogenetic_isolation <- mean(Evolutionary_distinctiveness)

      ## 4d) Phylogenetic isolation -- Variance of species isolation metrics

      #var(ED)

      variance_Phylogenetic_isolation <- var(Evolutionary_distinctiveness)
      cat("-")

      ## Tree topology

      #Gamma index

      ltts <- ltt(this_tree, gamma = TRUE, plot = FALSE)
      lineages_through_time <- as.numeric(ltts[[1]])
      time_steps <- as.numeric(ltts[[2]])
      gamma <- ltts[[3]]
      gamma_p_value <- ltts[[4]]
      cat("-")

      ##### (5) Tree metric -- Macroevolutionary - Rate and rate changes ###############
      ##################################################

      ## Speciation vs extinction rates and Net diversification
      bds <- bd(this_tree)
      speciation_rate <- bds[1]
      extinction_rate <- bds[2]
      extinction_per_speciation <- bds[3]
      speciation_minus_extinction <- bds[4]
      cat("-")

      ## Speciation vs extinction rates and Net diversification dependent on trait
      N.for.dom <- table(this_world[, 6])
      if(length(N.for.dom) == 2) {
        par.div.dep <- DivDep( mytree = this_tree, myWorld = this_world)
        trait_1_speciation <- par.div.dep[1]
        trait_2_speciation <- par.div.dep[2]
        trait_1_extinction <- par.div.dep[3]
        trait_2_extinction <- par.div.dep[4]
        transition_from_trait_1_to_2 <- par.div.dep[5]
        transition_from_trait_2_to_1 <- par.div.dep[6]
        transition_rate_ratio_1to2_over_2to1 <- transition_from_trait_1_to_2/transition_from_trait_2_to_1
        cat("-")

        ## Crown age per trait AUC and effect size
        tip.length <- this_tree$edge.length[this_tree$edge[, 2] %in% 1:Ntip(this_tree)]
        tip.length <- (tip.length - min(tip.length)) / (max(tip.length) - min(tip.length))
        this_trait <- this_world[match(this_tree$tip.label, this_world[, 8]), 6]
        tip.length.2 <- tip.length[this_trait == 2]
        tip.length.1 <- tip.length[this_trait == 1]
        model <- glm(as.factor(this_trait) ~ log(tip.length + 1),
                     family = "binomial")
        effect.size <- model$coefficients[2]
        plot(y = this_trait - 1, x= log(tip.length))
        p <- predict(model, as.factor(this_trait), type = "resp")
        points(y = p, x = log(tip.length), col = "red")
        pr <- prediction(p, as.factor(this_trait))
        auc.model <- performance(pr, measure = "auc")@y.values[[1]]

        ## Phylogenetic signal (D)
        Phylogenetic_signal <- Dsig(mytree = this_tree, myWorld = this_world)
        cat("-")

        ## Spatial Analysis
        nbs0 <- knearneigh(as.matrix(this_world[, 2:3]), k = 7, longlat = TRUE)
        nbs <- knn2nb(nbs0, sym = TRUE) # 7 symmetric neighbors
        nbs.listw <- nb2listw(nbs)
        factors.nbs <- as.factor(ifelse(is.na(this_world[, 6]), 3, this_world[, 6]))
        spatial.tests <- joincount.test(fx = factors.nbs, listw = nbs.listw)
        spatial.tests.fora <- spatial.tests[[1]]$statistic
        spatial.tests.dom <- spatial.tests[[2]]$statistic
        prevalence <- (N.for.dom[1] - N.for.dom[2]) / sum(N.for.dom)
        cat("-")
      } else {
        trait_1_speciation <- NA
        trait_2_speciation <- NA
        trait_1_extinction <- NA
        trait_2_extinction <- NA
        transition_from_trait_1_to_2 <- NA
        transition_from_trait_2_to_1 <- NA
        transition_rate_ratio_1to2_over_2to1 <- NA
        Phylogenetic_signal <- NA
        spatial.tests.fora <- NA
        spatial.tests.dom <- NA
        auc.model <- NA
        effect.size <- NA
        prevalence <- ifelse(names(table(this_world[, 6])[1]) == "1", 1,
                             -1)
        cat("---")

      }

      results_summary_matrix_1 <- cbind(

        number_of_branches,
        Pylo_diversity_is_sum_of_BL,
        average_phylogenetic_diversity_is_mean_of_BL,
        variance_Pylo_diversity_is_variance_of_BL,

        F_quadratic_entropy_is_sum_of_PD,
        Mean_pairwise_distance,
        variance_pairwise_distance,

        Evolutionary_distinctiveness_sum,
        mean_Phylogenetic_isolation,
        variance_Phylogenetic_isolation,

        gamma,
        gamma_p_value,
        speciation_rate,
        extinction_rate,
        extinction_per_speciation,
        speciation_minus_extinction,
        trait_1_speciation,
        trait_2_speciation ,
        trait_1_extinction ,
        trait_2_extinction ,
        transition_from_trait_1_to_2 ,
        transition_from_trait_2_to_1 ,
        transition_rate_ratio_1to2_over_2to1 ,
        Phylogenetic_signal,
        spatial.tests.fora,
        spatial.tests.dom,
        prevalence,
        auc.model,
        effect.size
      )
      rownames(results_summary_matrix_1) <- 1

      results_summary_matrix_2 <- cbind(
        c(Evolutionary_distinctiveness,NA),
        lineages_through_time,
        time_steps
      )
      colnames(results_summary_matrix_2) <- c("Evolutionary_distinctiveness", "lineages_through_time", "time_steps")
     # head(results_summary_matrix_2)

      ### Returns from function in list form
      returns <- list(
        #Branch_Lengths,
        #Pairwise_dist,
        results_summary_matrix_1,
        results_summary_matrix_2

      )

      names(returns) <- c(
        #"Branch_Lengths",
        #"Pairwise_distance",
        "results_summary_of_single_value_outputs",
        "results_summary_matrix_of_multi_value_outputs"
      )
      cat("] 100%")

      

    }
  


#Module_2(myOut)

Including Plots

You can also embed plots, for example:

Note that the echo = FALSE parameter was added to the code chunk to prevent printing of the R code that generated the plot.

Nielsen et al. (2017)

Module 2: Space and phylogeny summary statistics

This is the master document for Module 2, a foundational function in our FARM package that analyzes results from Module 1, the other foundational function. Module 1 simulates a spatial pattern and a phylogenetic tree given a set of environmental and inheritance rules and then Module 2 summarizes those simulated results using a large set of targeted summary statistics. Here we describe our choice of summary statistics, justify those choices as part of a larger theoretical context, and provide our reproducable code for executing the anaylses yourself. These two parts are seperated into modules so that they can act independently. An combination of spatial pattern and associated phylogeny many be used as long as they are formatted correctly.

This pipeline was designed to analyze a simulated world where all the information is known about both the world and the tree. There is no missing information, just extinct trees. This is much different than our real tree that has loads of uncertainty unevenly destributed across it. The result you see demonstrated right now are one simulated result of many. I need to do a sister page to this were we do this entire analysis on the real tree, or best real tree we’ve got.

We have four types of data available for asking research questions using D-place data: phylogenies, spatial locations, trait identities, and environmental reconstructions. Any one of these four data types alone are relatively information poor, so we are searching for ways to model connections between these data types to draw stronger conclusions overall.

Other modules can use the summary statistics generated from this module to test hypotheses. We currently have a ABC and Random Forest module started but there will be more to come.

These are quantitative connections that we are assumed in the analyses, but we don’t actually have any support in the data for doing so. 1. nearest neighbor connectivity measures 2. Abundance estimates 3. Pairwise influence (history) between cultures. 4. Environmental reconstruction validation evidence

Phylogenetic summary statistics

Whole tree vs. part of tree? These statistics are generally used to compare one sample to another. For example, an experimental contrast between two sites, two phylogenetic groups, or two communities in two different locations. Here we are calculating these statistics for the global langauage tree to compare against global trees created in our simulation. You still retain the ability to subset this tree or others and send only those subsets through this code to compare the values with each other afterwards.

  1. Branch Length (richness and divergence)
  2. Pairwise distance between tips (richness, divergence, and regularity)
  3. Phylogenetic isolation (divergence, and regularity)
  4. Nearest Neighbor (divergence, and regularity)

All trees are ultrametric.

Introduction and framework

The choice of phylogenetic analyses and organizational scheme is based on the suggestions of Tucker et al. 2016. Here are a few images from that paper for an overview:

From Tucker et al. 2016. Biological Reviews From Tucker et al. 2016. Biological Reviews

From Tucker et al. 2016. Biological Reviews

From Tucker et al. 2016. Biological Reviews

From Tucker et al. 2016. Biological Reviews

From Tucker et al. 2016. Biological Reviews

#load('~/Downloads/FULL_TREE_Society_data_with_binary_conversions.Rdata')

load('~/Downloads/Tree_FULL_trimmed.Rdata')

this_tree <- full_tree 


load('~/Downloads/download.Rdata')

#str(myOut)

this_tree <- myOut$mytree
this_world <- myOut$myWorld

#str(this_world)
  #str(all_trees)
  #str(this_tree)


#library(knitr)
#kable(this_world, caption= "This is our world")

Alpha diversity metrics

Branch Lengths

Branch length data is embedded in the tree object provided to this function. The first step in summarizing the lengths is to extract those data from the tree object. These data are called ‘edges’ in the tree object. We extract branch lengths and create an object called ‘Branch_lengths’ for passing on to the other summary functions. The histogram below shows the frequency of different branch lengths found throughout the tree.

      Branch_Lengths <- this_tree$edge.length

We can summarize branch lengths according to normal summary statistics, but it can be difficult to assign evolutionary meaning to some of these metrics and so they are not regularly used as best I can tell. This lack of meaning does not mean that these statistics couldn’t be used to distinguish between large simulated trees.

      mean_branch_length <- mean(Branch_Lengths)
      variance_branch_length <- var(Branch_Lengths)
      SD_branch_length <- sd(Branch_Lengths)

Phylogenetic diversity (\(PD\))

Phylogenetic diversity (\(PD\)) is the summation (\(\sum\)) of all branch lengths connecting species together, where \(B_{t}\) is the set of included tips and \(L_{b}\) is Branch lengths. (Faith 1992) This is an anchor test, which means it is regularly used, well understood, and we should use it to anchor our work to past work. PD is a richness measure, it tells us how much evolutionary history is associated with a set of tips.

\[PD = \sum_{b \in B_{t}}^{}L_{b}\]


# Anchor test = PD (Faith's phylogenetic diversity)
      Pylo_diversity_is_sum_of_BL <- sum(Branch_Lengths)
      Pylo_diversity_is_sum_of_BL

There are variations on this measure that we have NOT implemented here. It is popular to scale this measure according to some ecological driver. Barker (2002) scales branch lengths (\(L_{b}\)) by multiplying them against the abundance of individuals at at tip (\(A_{b}\)). Others (Rosauer et al. 2009), scale them by their range size instead (\(R_{b}\)).

\[\Delta n PD = \sum_{b \in B_{t}}^{}A_{b}L_{b}\] \[PE = \sum_{b \in B_{t}}^{}\dfrac{L_{b}}{R_{b}}\] Argueing that proportional abundance phylogenetic diversity (\(PD_{Ab}\)) is more effective than the standard PD calculated from raw abundance, Vellend et al. penned a new version of PD where \(B\) is the total number of branch lengths (\(L_{b}\)). Note: We don’t have abundance data right now for the human project so this metric is not currently very helpful.
\[PD_{Ab} = B * \dfrac{\sum_{b \in B_{t}}^{}A_{b}L_{b}}{\sum_{b \in B_{t}}^{}A_{b}}\]

      #Calculate B
      number_of_branches <- length(Branch_Lengths)
      number_of_branches

Average phylogenetic diversity (\(avPD\))

Average phylogenetic diversity (\(avPD\)) (introduced by Clarke and Warwick 2001) is a branch length-based divergence indices where PD is divided by the total number of tips (\(S\)) in the tree. \[avPD = \dfrac{PD}{S}\]

      Number_of_tips <- length(this_tree$tip.label)
      average_phylogenetic_diversity <- Pylo_diversity_is_sum_of_BL / Number_of_tips
      average_phylogenetic_diversity

There is also a proportional abundance version of average phylogenetic diversity (\(avPD_{Ab}\)) (Tucker et al. 2016). Again, we don’t have abundance values yet for D-place. \[avPD_{Ab} = \dfrac{B * \dfrac{\sum_{b \in B_{t}}^{}A_{b}L_{b}}{\sum_{b \in B_{t}}^{}A_{b}}}{S}\]

Pairwise distance between tips

This is the patristic distance, the sum of the branch lengths following the shortest distance between two tips in a tree, implemented as a distance matrix where every tip is compared to every other tip. This distance function can be anything. We use euclidean and environmental distance matrices heavily in the spatial analyses.

Calculate the patristic distance between two taxa, for all taxa

Calculate the patristic distance between two taxa using the R package ‘phytools’, this function takes a ‘phylo’ tree object and returns a distance matrix between tips. Need original citation.

    library(phytools)
  
    ls("package:phytools")
 ## Pairwise distance between tips - From library(ape) in library(phytools)
    Pairwise_dist <- cophenetic(this_tree)

yields a distance matrix (list of 2D matrices) of all distances between taxa.

Sum of all pairwise distances (\(F\))

Now we can use a set of summary statistics to describe those pairwise distances. The sum of all pairwise distances, \(F\), is formally called ‘Extensive quadratic entropy’. (Izsak and Papp (2000) and Szeidl (2002)). Just as it was with branch lengths, this is a richness measure and, accordingly, should be used to answer richness questions.

\[F = \sum_{i} \sum_{j} d_{ij}\]

      # F -- Extensive quadratic entropy
      F_quadratic_entropy_is_sum_of_PD <- sum(Pairwise_dist)

Mean pairwise distance (MPD)

Mean inter-species distances. The mean of all pairwise distances, \(MPD\) (a.k.a. \(AvTD\), and \(\Delta^{+}\)), is the mean distance between species. (Clarke and Warwick (1998), Webb et al. (2002, 2008), Kembel et al. (2010)) \[MPD = \dfrac{\sum_{ij} d_{ij}}{S(S-1)}\]

      # Anchor test = MPD (mean pairwise distance)

      Mean_pairwise_distance <- Pairwise_dist / (Number_of_tips * (Number_of_tips - 1) ) 
      

MPD anchored to the root

There is an extention to mean pairwise distance calculations from Helmus et al. (2007) called \(PSV\), \(PSR\), and \(PSE\), phylogenetic species variability, phylogenetic species richness, and phylogenetic species evenness. These measures take the basic pairwise distance calculations and anchor them to the root of the tree so distances have a common denominator. This extention is implemented by using the same equations, just with a constrained set of \(d_{ij}\) conditions. Specifically,

\[PSV = MPD = \dfrac{\sum_{ij} d_{ij}}{S(S-1)}\] \[PSR = \sum_{i} {(\dfrac{1}{S-1} \sum_{j} {d_{ij}})}\] \[PSE = \dfrac{S}{S-1} \sum_{ij} d_{ij}p_{i}p_{j}\]

with these specific values of \(d_{ij}\)

\[d_{ji}=0.5*(c_{ii} + c_{jj} - c_{ij}) \\ \ \\ or \\ \ \\ d_{ij} = 1 - c_{ij} / (\sqrt{c_{ii}c_{jj}}) \] and \[ c_{ii} = the \ sum \ of \ branch \ lengths \ from \ tip \ i \ to \ the \ root \ of \ the \ phylogenetic \ tree. \\ \ \\ c_{ij} = the \ sum \ of \ branch \ lengths \ from \ first \ common \ ancestor \ for \ i \ and \ j \ to \ the \ root. \]

Average distance between two randomly chosen species

\(J\), Intensive quadratic entropy, which is the average distance between two randomly chosen species. (Izsak and Papp 2000) \[J = \dfrac{\sum_{ij}d_{ij}}{S^2} \]

Simpson’s diversity index for pairwise distance

There has been a long effort to pen a phylogenetic analogy to a Simpson’s diversity index. (see Rao (1982), Clarke and Warwick (1998), Pavoine et al. (2005), Hardy and Senterre (2007), Webb et al. (2002, 2008), Kembel et al. (2010)). The conclusion seems to be that this measure is equivilent to scaling \(MPD\) by abundance \(p_{i}\) and \(p_{j}\) to get \(MPD_{Ab}\). This is also a special case of Rao’s Quadratic Entropy, \(Roe's QE\). Note: not using abundance measures yet for D-place data.

\[MPD_{Ab} = \sum_{i} \sum_{j} d_{ij} p_{i} p_{j}\]

Interspecific comparisons of pairwise distances

The interspecific variant (rather than the intraspecific default described above) defines the expected phylogenetic distance between two indivdiuals randomely drawn conditionally on the fact that they indivdulas from different species. \[InterMPD_{Ab} = \dfrac{\sum_{i} \sum_{j \ne i} d_{ij} p_{i} p_{j} }{\sum_{i} \sum_{j \ne i} d_{ij} p_{i} p_{j}} \]

Variance in pairwise distances (\(VPD\))

Variance in pairwise distances, \(VPD\) (a.k.a. \(VarTD\) and \(\Lambda^+\)), is a regularity indices. Clarke and Warwick (2001) Variance is relative to tips, \(S\), not to total branches (\(B\) from above). These are the residuals, they compare each individual pairwise connection to the overall mean.

\[VPD = \dfrac{1}{S(S-1)} (\sum_{i} \sum_{j \ne i} {(d_{ij} - MPD)^2})\]

    #Pairwise distance/all distances -- Variance of pairwise distances

      # Anchor test = VPD (variation of pairwise distance) #need to adjust to equation above. 

      variance_pairwise_distance <- var(as.vector(Pairwise_dist))

Variants of \(VPD\) are \(VPD_{ab}\) and \(InterPVD_{Ab}\), where variance is scaled by abundance or compared in and out of species. These are also regularity indices. \[ VPD_{Ab}= (\sum_{i} \sum_{j} n_{i} n_{j}) * \dfrac{\sum_{i} \sum_{j} n_{i} n_{j} (d_{ij} - MPD_{Ab})^2} {(\sum_{i} \sum_{j} n_{i} n_{j})^2 - \sum_{i} \sum_{j} (n_{i} n_{j})^2} \\ or \\ InterVPD_{Ab} = (\sum_{i} \sum_{j \ne i} n_{i} n_{j}) * \dfrac{\sum_{i} \sum_{j \ne i} n_{i} n_{j} (d_{ij} - InterMPD_{Ab})^2} {(\sum_{i} \sum_{j \ne i} n_{i} n_{j})^2 - \sum_{i} \sum_{j \ne i} (n_{i} n_{j})^2} \]

Nearest phylogenetic neighbor

Divergence indices

Divergence indices using nearest distance: \(MNTD\) and \(MNTD_{Ab}\), Mean nearest taxon distance and Abundance-weighted MNTD. (Webb et al. (2002,2008), Kembel et al. (2010)).

\(MNTD\), mean nearest taxon distance, is the mean shortest distance from a species to all other in the assemblage. Webb et al (2002, 2008), Kembel et al. (2010)
\[ MNTD = \dfrac{1}{S} \sum_{i} d_{i_{min}} \]

\(MNTD_{AB}\), abundance adjusted mean nearest taxon distance. Adjusted by species proportions (i.e. species’ relative abundances) Webb et al (2002, 2008), Kembel et al. (2010)
\[ MNTD_{Ab} = \sum_{i=1}^{S} [d_{i_{min}} * p_{i}] \]

Regularity indices

Regularity indices using nearest distances: \(VNTD\), \(VNTD_{Ab}\), \(PE_{ev}\).

\(VNTD\), Variance in nearest taxon distances, is the variance in nearest pairwise distance. Tucker et al. (2016) \[ VNTD = \dfrac{1}{S} \sum_{i-1}^{S} [(d_{i_{min}} - MNTD)^2] \] \(VNTD_{Ab}\), Abundance weighted variance in nearest taxon distances, is scales by abundance in the same way as descried above. Tucker et al. (2016) \[ VNTD_{Ab} = \dfrac {(\sum_{i} n_{i}) \sum_{i} n_{i} (d_{i_{min}} - MNTD_{Ab})^2} {(\sum_{i} n_{i})^2 - \sum_{i} n_{i} ^2} \]

Phylogenetic version of the funtional \(FE_{ve}\) index

\(PE_ve\), phylogenetic evenness is a phylogenetic version of the funtional \(FE_{ve}\) index. First a minimu spannin tree (MST) is computed using the cophenetic distance obtained from the phylogenetic tree. The MST contains S-1 Branches connection the S species. We denote l a branch on the MST, dist(i,j) is the lengththe branch l that connects species i and j. ni is, as defined abouve, the abundce of species i in the asseblage. Villeger et al. (2008), Dehling et al. (2014).

\[ Weighted \ evenness: \\ EW_{i} = \dfrac{dist(i,j)} {(n_{i} + n_{j})/(\sum_{k=1}^{S}n_{k})} \\ \ \\ Partial \ weighted \ evenness: \\ PEW_{l} = \dfrac {EW_{l}} {\sum_{l=1}^{S-1} EW_{l}} \\ \ \\ Phylogenetic \ evenness: \\ PE_{ve} = \dfrac {\sum_{l=1}^{S-1} min(PEW_{l}, \dfrac{1}{S-1}) - (\dfrac{1}{S-1})} {1- (\dfrac{1}{S-1})} \]

Phylogenetic isolation

A phylogenetic isolation index represents the relative isolation of a given species within a phylogenetic tree. Several indices have been proposed so far but we focus here on the evolutionary distinctiveness index called ‘Fair Proportion’ as proposed by Redding (2003) and Isaac (2007).

Evolutionary distinctiveness (richness indices)

\(ED\), evolutionary distinctiveness is a richness indices. NOTE: not equal to Faith’s PD because the \(ED_{i}\) are computed from the regional pool of species and sumed across a given assemblage (i.e. a subset of the regional species pool). Tucker (2016), Safi et al. (2013), Redding (2003), and Isaac (2007)

\[ ED = \sum_{i}ED_{i} \\ \ \\ where \ ED_{i} = \sum_{b \in B_{t_{i}}} \dfrac{L_{b}}{S_{b}} \]

\(AED\), Abundance-weighted \(ED\). Tucker (2016) and Cadotte et al. (2010) \[ \sum_{i} AED_{i} \\ \ \\ where \ AED_{i} = \sum_{b \in B_{t_{i}}} \dfrac{L_{b}}{A_{b} }* p_{i} \]


# Bruno's function for ED. Provided in library(FARM)

evol.distinct2 <- function (tree, type = c("equal.splits", "fair.proportion"), 
    scale = FALSE, use.branch.lengths = TRUE) 
{
    type <- match.arg(type)
    if (is.rooted(tree) == FALSE) 
        warning("A rooted phylogeny is required for meaningful output of this function", 
            call. = FALSE)
    if (scale == TRUE) {
        if (is.ultrametric(tree) == TRUE) 
            tree$edge.length <- tree$edge.length/(as.numeric(branching.times(tree)[1]))
        else tree$edge.length <- tree$edge.length/sum(tree$edge.length)
    }
    if (use.branch.lengths == FALSE) 
        tree$edge.length <- rep(1, length(tree$edge.length))
    for (i in 1:length(tree$tip.label)) {
        spp <- tree$tip.label[i]
        nodes <- .get.nodes(tree, spp)
        nodes <- nodes[1:(length(nodes) - 1)]
        internal.brlen <- tree$edge.length[which(tree$edge[, 
            2] %in% nodes)]
        if (length(internal.brlen) != 0) {
            internal.brlen <- internal.brlen * switch(type, equal.splits = sort(rep(0.5, 
                length(internal.brlen))^c(1:length(internal.brlen))), 
                fair.proportion = {
                  for (j in 1:length(nodes)) {
                    sons <- .node.desc(tree, nodes[j])
                    n.descendents <- length(sons$tips)
                    if (j == 1) portion <- n.descendents else portion <- c(n.descendents, 
                      portion)
                  }
                  1/portion
                })
        }
        ED <- sum(internal.brlen, tree$edge.length[which.edge(tree, 
            spp)])
        if (i == 1) 
            w <- ED
        else w <- c(w, ED)
    }
    return(w)
}

Evolutionary distinctiveness is our basic measure of phylogenetic isolation. #This should likely be ‘fair proportions’ instead of ‘equal.splits’.

      library(phytools)
      library(FARM)
      # Calculate ED
      # Using equal.splits method, faster computation
     # Evolutionary_distinctiveness_i <- evol.distinct2(this_tree, type = "equal.splits")  
      
      # ED - Summed evolutionary distinctiveness
     # Evolutionary_distinctiveness_sum <- sum(Evolutionary_distinctiveness_i)
#Evolutionary_distinctiveness_sum

We can run some standard summary statistics (mean and variance) on this ED measure. var(Ed) shows up close to VPD on the PCAs in the intro. Tucker(2016)

      # mean(ED)
     # mean_Phylogenetic_isolation <- mean(Evolutionary_distinctiveness_i)
      
      # var(ED)
      #variance_Phylogenetic_isolation <- var(Evolutionary_distinctiveness_i)
#mean_Phylogenetic_isolation
#variance_Phylogenetic_isolation

Mean evolutionary distinctiveness (divergence indices)

The divergence indices version for \(ED\) is mean evolutionary distinctiveness, \(MED\). The mean of evolutionary distinctiveness. Redding (2003) and Isaac (2007) \[ MED = \dfrac {\sum_{i} ED_{i}} {S} \\ \ \\ with \\ \ \\ ED_{i} = \sum_{b \in B_{t_{i}}} \dfrac{L_{b}}{S_{b}} \] #### Entropy measure of evolutonary distinctiveness (regularity indices) The regularity indices for \(ED\)/phylogenetic isolation are \(H_{ED}\), \(E_{ED}\), \(var(ED)\), \(H_{AED}\)

\(H_{ED}\), Entropy measure of evolutionary distinctiveness, is the shannon index applied to evolutionary distinctiveness values. Cadotte et al. (2010) \[ H_{ED} = -\sum_{i=1}^{S} ((\dfrac{ED_{i}}{\sum_{i=1}^{S} ED_{i}}) * \ln (\dfrac{ED_{i}}{\sum_{i=1}^{S} ED_{i}})) \]

\(E_{ED}\), Equitability of evolutionary distinctiveness, is \(H_{ED}\) controlled for species richness. Cadotte et al. (2010)

\[ E_{ED} = \dfrac{H_{ED}}{\ln(S)} \] \(var(ED)\), Variance in evolutinoary distinctiveness, is the variance of species evolutionary distinctiveness. Tucker (2016)

\[ var(ED) = \dfrac{1}{S-1} * \sum_{i=1}^{S} (ED_{i}-\dfrac{\sum_{i=1}^{S} ED_{i}}{S})^2 \] \(H_{ED_{Ab}}\), Abundance-weighted version of \(H_{ED}\). Cadotte et al. (2016)

\[ H_{ED_{Ab}} = -\sum_{i=1}^{S} (\dfrac{n_{i}AED_{i}}{\sum_{i=1}^{S} n_{i}AED_{i}} * \ln(\dfrac{n_{i}AED_{i}}{\sum_{i=1}^{S} n_{i}AED_{i}})) \]

Beta diversity

Beta-diversity indices I. Richness indices (presence–absence data) II. Divergence indices (using pairwise distances among species) 1. Presence/absence data A. Decomposition into , , diversities B. Direct dissimilarities 1. Using all distances 2. Using nearest distances 2. Abundance data A. Decomposition into , , diversities B. Direct dissimilarities III. Parametric indices 1. Equivalent numbers 2. Entropy

Tree topology

Tree topology is a measure of the shape of the overall tree. The tree can be lopsided side-to-side or front-to-back.

Our most trusted index for the tippy vs trunky of a tree is the gamma index, \(\gamma\).The index characterizes the distribution of branching events within the tree. Trees with γ < 0 have relatively longer branches towards the tips of the phylogeny (tippy trees), whereas trees with γ > 0 have relatively longer inter-nodal distances towards the root of the phylogeny (stemmy trees). tk represents an ‘evolutionary period’ (limits are given by two speciation events) or equivalently an internode distance. Pybus and Harvey (2000)

\[ \gamma = \dfrac {(\dfrac{1}{S-2}* \sum_{i=2}^{S-1} (\sum_{k=2}^{i} Kt_{k}))- \dfrac{1}{2} * \sum_{j=2}^{S} jt_{j}} {(\sum_{j=2}^{S} jt_{j}) * \sqrt{\dfrac{1}{12*(S-2)}}} \]

      library(phytools)
      
      ltts <- ltt(this_tree, gamma = TRUE, plot = FALSE)
ltts
str(ltts)
      lineages_through_time <- as.numeric(ltts[[1]])
      time_steps <- as.numeric(ltts[[2]])
      #extract Gamma index
      gamma <- ltts[[3]]
      gamma_p_value <- ltts[[4]]
lineages_through_time 
time_steps 
gamma 
gamma_p_value 

There are two other regularly used metrics that include abundance measures. Note: we don’t have abundance measures for D-place data.

\(IAC\), imbalance of abundance at the clade level, quantifies the relative deviation in the abundance distribution from a null case where individuals are evenly partitioned between clade splits. \(v\) is the number of nodes in the phylogenetic tree. \(n_{i}\) is, as defined above, the abundance of species \(i\) in the assemblage. \(\eta_{k}\) is the expected abundance species \(i\) would have if the abundance was randomly split among lineages in the phylogenetic tree at each speciation event. is the number of lineages originating at node \(k\) in the set \(s(k,root)\), which contains the nodes located on the path between node \(k\) and the root of the phylogenetic tree. N is the total assemblage abundance. Cadotte et al. (2010)

\[ \dfrac{\sum_{i=1}^{S} |n_{i} - \hat{n_{i}}|} {v} \\ \ \\ where \\ \ \\ \hat{n_{i}} = \dfrac{N}{\prod_{K \in s(i, root)}\eta_{k}} \]

\(I_{c}\), the Colless index, is the sum of the absolute differences in species richness between sister-clades at each internal node. For fully resolved trees, each internal node defines two sister-clades. \(S_{1k}\) is the number of species descending from the first clade defined by node k and \(S_{2k}\) that of the second clade. \(v\) is, as defined above, the number of nodes in the phylogenetic. Colless (1982)

\[ I_{c} = \sum_{k=1}^{v} |S_{1k} - S_{2k}| \]

Macroevolutionary rates


#function name = bd, function input = tree of type 'phylo'
print(bd) 
 ## Speciation vs extinction rates and Net diversification
     

      bds <- bd(this_tree)
      speciation_rate <- bds[1]
      extinction_rate <- bds[2]
      extinction_per_speciation <- bds[3]
      speciation_minus_extinction <- bds[4]
  

      ## Speciation vs extinction rates and Net diversification dependent on trait
     # N.for.dom <- table(this_world[, 6])
  #    if(length(N.for.dom) == 2) {
        par.div.dep <- DivDep( mytree = this_tree, myWorld = this_world)
        trait_1_speciation <- par.div.dep[1]
        trait_2_speciation <- par.div.dep[2]
        trait_1_extinction <- par.div.dep[3]
        trait_2_extinction <- par.div.dep[4]
        transition_from_trait_1_to_2 <- par.div.dep[5]
        transition_from_trait_2_to_1 <- par.div.dep[6]
        transition_rate_ratio_1to2_over_2to1 <- transition_from_trait_1_to_2/transition_from_trait_2_to_1
      
library(ROCR)
        ## Crown age per trait AUC and effect size
        tip.length <- this_tree$edge.length[this_tree$edge[, 2] %in% 1:Ntip(this_tree)]
        tip.length <- (tip.length - min(tip.length)) / (max(tip.length) - min(tip.length))
        this_trait <- this_world[match(this_tree$tip.label, this_world[, 8]), 6]
        tip.length.2 <- tip.length[this_trait == 2]
        tip.length.1 <- tip.length[this_trait == 1]
        model <- glm(as.factor(this_trait) ~ log(tip.length + 1),
                     family = "binomial")
        effect.size <- model$coefficients[2]
       # plot(y = this_trait - 1, x= log(tip.length))
        p <- predict(model, as.factor(this_trait), type = "resp")
       # points(y = p, x = log(tip.length), col = "red")
        pr <- prediction(p, as.factor(this_trait))
        auc.model <- performance(pr, measure = "auc")@y.values[[1]]

      
  ## Phylogenetic signal (D)
        Phylogenetic_signal <- Dsig(mytree = this_tree, myWorld = this_world)
        

Spatial Locations


library(spdep)
 ## Spatial Analysis
        nbs0 <- knearneigh(as.matrix(this_world[, 2:3]), k = 7, longlat = TRUE)
        nbs <- knn2nb(nbs0, sym = TRUE) # 7 symmetric neighbors
        nbs.listw <- nb2listw(nbs)
        factors.nbs <- as.factor(ifelse(is.na(this_world[, 6]), 3, this_world[, 6]))
        spatial.tests <- joincount.test(fx = factors.nbs, listw = nbs.listw)
        spatial.tests.fora <- spatial.tests[[1]]$statistic
        spatial.tests.dom <- spatial.tests[[2]]$statistic
        #prevalence <- (N.for.dom[1] - N.for.dom[2]) / sum(N.for.dom)
results_summary_matrix_1 <- cbind(

        number_of_branches,
        #Pylo_diversity_is_sum_of_BL,
        #average_phylogenetic_diversity_is_mean_of_BL,
        #variance_Pylo_diversity_is_variance_of_BL,

        F_quadratic_entropy_is_sum_of_PD,
        Mean_pairwise_distance,
        variance_pairwise_distance,

        #Evolutionary_distinctiveness_sum,
        #mean_Phylogenetic_isolation,
        #variance_Phylogenetic_isolation,

        gamma,
        gamma_p_value,
        speciation_rate,
        extinction_rate,
        extinction_per_speciation,
        speciation_minus_extinction,
        trait_1_speciation,
        trait_2_speciation ,
        trait_1_extinction ,
        trait_2_extinction ,
        transition_from_trait_1_to_2 ,
        transition_from_trait_2_to_1 ,
        transition_rate_ratio_1to2_over_2to1 ,
        Phylogenetic_signal,
        spatial.tests.fora,
        spatial.tests.dom,
       # prevalence,
       # auc.model,
        effect.size
      )
      #rownames(results_summary_matrix_1) <- 1

      #results_summary_matrix_2 <- cbind(
      #  c(Evolutionary_distinctiveness,NA),
      #  lineages_through_time,
      #  time_steps
      #)
      #colnames(results_summary_matrix_2) <- c("Evolutionary_distinctiveness", "lineages_through_time", "time_steps")
      #head(results_summary_matrix_2)

      ### Returns from function in list form
      #returns <- list(
        #Branch_Lengths,
        #Pairwise_dist,
      #  results_summary_matrix_1,
      #  results_summary_matrix_2

      #)

      #names(returns) <- c(
        #"Branch_Lengths",
        #"Pairwise_distance",
       # "results_summary_of_single_value_outputs",
       # "results_summary_matrix_of_multi_value_outputs"
      #)
      
      

Module2() returns these two matrices as a list

Running an R script on the cluster requires two parts: an R script with the code to be run and a PBS script to control how that R script is run on the cluster.

There are two different clusters at Wustl.edu, an old and a new cluster. This script runs the R code on the new cluster.

#!/bin/bash
#PBS -N Four_model_run 
#PBS -V                     
#PBS -l walltime=23:59:00               
#PBS -l pmem=1200mb 
#PBS -l nodes=1:ppn=1:haswell 
#PBS -t 1-1000


echo $PBS_ARRAYID

cd /home/cbotero/mydirectory/Four_model_compare
module load R

export R_LIBS=$HOME/rlibs
#R CMD INSTALL --library=/home/ttuff/rlibs  FARM_1.0.tar.gz

Rscript --vanilla ./FARM_four_model_compare.R ${PBS_ARRAYID}

We were regularly causing problems running to many jobs on the new cluster and we were asked to move to the old cluster. This cluster has slower individual processors, but we can run more jobs at one time, so productivity has stayed about the same.

#!/bin/bash
#PBS -N FARM_third_run_old 
#PBS -V                     
#PBS -l walltime=160:00:00              
#PBS -l pmem=1200mb 
#PBS -q old
#PBS -l nodes=1:ppn=1:nehalem 
#PBS -t 1-500


echo $PBS_ARRAYID

cd /home/ttuff/mydirectory/Four_model_compare
module load R

export R_LIBS=$HOME/rlibs
#R CMD INSTALL --library=/home/ttuff/rlibs  FARM_1.0.tar.gz

Rscript --vanilla ./FARM_four_model_compare.R ${PBS_ARRAYID} 

The final argument in the #PBS script above (#PBS -t 1-500) controls the serial running schema for running many simultanious instances of the R script at a time. This argument is passes to R as an integer value using the following arguements inside R.


args <- commandArgs(trailingOnly = FALSE) #7 elements are passed from the PBS

NAI <- as.numeric(args[7]) # the seventh of those elements is the array integer.

Here is a working example of how to set up the R script.

#install.packages("rfoaas")
library(rfoaas)

##If the PBS script started this code running and passed the number 13
##to this particular run of a larger serial set. 


#args <- commandArgs(trailingOnly = FALSE) 

NAI <- 13 #as.numeric(args[7])

    sayHello <- function(loop_number){
      print(paste0("I can count to ", loop_number, "!   ", cool(from="Ty")))
    }

    sayHello(NAI)

You logon to the cluster using linux/unix code from the command line terminal on you computer. Open the terminal and put in you login info.

ssh -Y ttuff@login.chpc.wustl.edu
password:_______

Upon first login, you will be in a folder called ‘HOME’ with a series of system files in it. You will want to use an FTP client to view and organize these files. I prefer Filezilla, but there are several other good clients available for free. Download filezilla, make sure it’s in your applications folder, and open it. You should see a window that looks like a newer version of this. The left panels are the files on the computer you’re working from and the right two panels will show the files on the server once you log in through Filezilla also.

A fresh Filezilla window

A fresh Filezilla window

Start a new server link

Start a new server link

Start a new site and name that new site

Start a new site and name that new site

Select a secure ssh file transfer protocol

Select a secure ssh file transfer protocol

Login as normal

Login as normal

Enter password

Enter password

You need to create two new directories (folders) for us to work out of. Call one rlibs and the other mydirectory

You need to create two new directories (folders) for us to work out of. Call one ‘rlibs’ and the other ‘mydirectory’

Within mydirectory, create another folder called Four_model_compare

Within mydirectory, create another folder called ‘Four_model_compare’

Within Four_model_compare, create two folders called Module_1_outputs and Module_2_outputs. Then drag three files from your computer files on the left to the server folders on the right: one .R file, one .pbs file, and a zip file with the package FARM in it. These should be named FARM_four_model_compare.R, FARM_four_model_compare_old_cluster.pbs, and FARM_1.0.tar.gz .

Within ‘Four_model_compare’, create two folders called ‘Module_1_outputs’ and ‘Module_2_outputs’. Then drag three files from your computer files on the left to the server folders on the right: one .R file, one .pbs file, and a zip file with the package FARM in it. These should be named FARM_four_model_compare.R, FARM_four_model_compare_old_cluster.pbs, and FARM_1.0.tar.gz .

Once logged in, you need to change the directory

cd /home/ttuff/mydirectory/Four_model_compare

Barker, Gary M. 2002. “Phylogenetic diversity : a quantitative framework for measurement of priority and achievement in biodiversity conservation.” Biological Journal of the Linnean Society 76: 165–94. http://www.jstor.org/stable/3070944?seq=1{\#}page{\_}scan{\_}tab{\_}contents.

Cadotte, Marc W., T. Jonathan Davies, James Regetz, Steven W Kembel, Elsa Cleland, and Todd H. Oakley. 2010. “Phylogenetic diversity metrics for ecological communities : integrating species richness, abundance and evolutionary history.” Ecology Letters 13: 96–105. doi:10.1111/j.1461-0248.2009.01405.x.

Clarke, KR, and RM Warwick. 1998. “Quantifying structural redundancy in ecological communities.” Oecologia 113: 278–89. http://link.springer.com/article/10.1007/s004420050379.

———. 2001. “A further biodiversity index applicable to species lists: variation in taxonomic distinctness.” Marine Ecology Progress Series 216: 265–78. http://researchrepository.murdoch.edu.au/id/eprint/23107/.

Colless, Donald H. 1982. “Review of phylogenetics: the theory and practice of phylogenetic systematics.” Systematic Zoology 31 (1): 100–104. http://www.jstor.org/stable/2413420.

Dehling, D Matthias, Susanne A Fritz, Till Töpfer, Martin Päckert, Patrizia Estler, Katrin Böhning-gaese, and Matthias Schleuning. 2014. “Functional and phylogenetic diversity and assemblage structure of frugivorous birds along an elevational gradient in the tropical Andes IBS special issue.” Ecography 37: 1047–55. doi:10.1111/ecog.00623.

Faith, Daniel P. 1992. “Conservation evaluation and phylogenetic diversity.” Biological Conservation 61: 1–10. http://www.sciencedirect.com/science/article/pii/0006320792912013.

Hardy, Olivier J, and Bruno Senterre. 2007. “Characterizing the phylogenetic structure of communities by an additive partitioning of phylogenetic diversity.” Journal of Ecology 95: 493–506. doi:10.1111/j.1365-2745.2007.01222.x.

Helmus, Matthew R, Wendel (Bill) Keller, Michael J Paterson, Norman D Yan, Charles H Cannon, and James A Rusak. 2010. “Communities contain closely related species during ecosystem disturbance.” Ecology Letters 13: 162–74. doi:10.1111/j.1461-0248.2009.01411.x.

Isaac, Nick J B, Samuel T Turvey, Ben Collen, Carly Waterman, and Jonathan E M Baillie. 2007. “Mammals on the EDGE : Conservation Priorities Based on Threat and Phylogeny.” PLoS ONE 2 (3): e296. doi:10.1371/journal.pone.0000296.

Kembel, Steven W, Peter D Cowan, Matthew R Helmus, William K Cornwell, Helene Morlon, David D Ackerly, Simon P Blomberg, and Campbell O Webb. 2010. “Picante : R tools for integrating phylogenies and ecology.” Bioinformatics 26 (11): 1463–4. doi:10.1093/bioinformatics/btq166.

Nielsen, Rasmus, Joshua M Akey, Mattias Jakobsson, Jonathan K Pritchard, Sarah Tishkoff, and Eske Willerslev. 2017. “Tracing the peopling of the world through genomics.” Nature 541: 302–10. doi:10.1038/nature21347.

Pavoine, S Ã, S Ollier, and D Pontier. 2005. “Measuring diversity from dissimilarities with Rao’s quadratic entropy: Are any dissimilarities suitable?” Theoretical Population Biology 67 (4): 231–39. doi:10.1016/j.tpb.2005.01.004.

Pybus, Oliver G, and Paul H Harvey. 2000. “Testing macro-evolutionary models using incomplete molecular phylogenies.” Proceedings of the Royal Society B 267 (1459): 2267–72. doi:10.1098/rspb.2000.1278.

Rao, Radhakrishna C. 1982. “Diversity and Dissimilarity coefficients: a unified approach.” Theoretical Population Biology 21: 24–43. http://www.sciencedirect.com/science/article/pii/0040580982900041.

Rosauer, Dan F, Shawn W Laffan, Michael D Crisp, and Stephen C Donnellan. 2009. “Phylogenetic endemism : a new approach for identifying geographical concentrations of evolutionary history.” Molecular Ecology 18: 4061–72. doi:10.1111/j.1365-294X.2009.04311.x.

Safi, Kamran, Katrina Armour-marshall, Jonathan E M Baillie, and Nick J B Isaac. 2013. “Global Patterns of Evolutionary Distinct and Globally Endangered Amphibians and Mammals.” PLoS ONE 8 (5): e63582–e63582. doi:10.1371/journal.pone.0063582.

Tucker, Caroline M., Marc W. Cadotte, Silvia B. Carvalho, T. Jonathan Davies, Simon Ferrier, Susanne A. Fritz, Rich Grenyer, et al. 2016. “A guide to phylogenetic metrics for conservation, community ecology and macroecology.” Biological Reviews. doi:10.1111/brv.12252.

Vellend, Mark, William K Cornwell, Karen Magnuson-ford, and Arne Ø Mooers. 2011. “Measuring phylogenetic biodiversity.” In Biological Diversity: Frontiers in Measurement and Assessment, 194–207. Oxford, UK: Oxford University Press. http://phylodiversity.net/wcornwell/Vellend{\_}etal{\_}2011{\_}bookchap.pdf.

Villeger, Sebastien, Norman WH Mason, and David Mouillot. 2008. “New multidimensional functional diversity indices for a multifaceted framework in functional ecology.” Ecology 89 (8): 2290–2301. http://onlinelibrary.wiley.com/doi/10.1890/07-1206.1/full.

Webb, Campbell O, David D Ackerly, and Steven W Kembel. 2008. “Phylocom: software for the analysis of phylogenetic community structure and trait evolution.” Bioinformatics 24 (18): 2098–2100. doi:10.1093/bioinformatics/btn358.

Webb, Campbell O, David D Ackerly, Mark A Mcpeek, and Michael J Donoghue. 2002. “Phylogenies and Community Ecology.” Annual Review of Ecology and Systematics 33: 475–505. doi:10.1146/annurev.ecolsys.33.010802.150448.

LS0tCnRpdGxlOiAnRC1wbGFjZSBGQVJNIGRvY3VtZW50YXRpb246IE1hc3RlciBzY3JpcHQnCmF1dGhvcjogIlR5IFR1ZmYsIEJydW5vIFZpbGVsYSwgYW5kIENhcmxvcyBCb3Rlcm8iCmRhdGU6ICdwcm9qZWN0IGJlZ2FuOiAxNSBNYXkgMjAxNiwgZG9jdW1lbnQgdXBkYXRlZDogYHIgc3RyZnRpbWUoU3lzLnRpbWUoKSwgZm9ybWF0CiAgPSAiJWQgJUIgJVkiKWAnCm91dHB1dDoKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKYmlibGlvZ3JhcGh5OiBGQVJNIHBhY2thZ2UuYmliCi0tLQoKVGhlcmUgYXJlIHR3byB2ZXJzaW9ucyBvZiB0aGlzIHNjcmlwdCwgdGhlIGZpcnN0IGlzIGZvciBydW5uaW5nIGVhY2ggc2ltdWxhdGlvbiB0byB0aGUgCmVuZCBhbmQgdGhlbiBzYXZpbmcgdGhlIGZpbmFsIHN0ZXAgYXMgdGhlIG91dHB1dCBvZiB0aGUgbW9kZWwgYW5kIHRoZSBzZWNvbmQgCmlzIHRvIHNhdmUgb3V0cHV0cyBhbG9uZyB0aGUgd2F5IHNvIHdlIGNhbiBldmFsdWF0ZSBob3cgZGlmZmVyZW50IG1vZGVscyBjaGFuZ2UgdGhyb3VnaCB0aW1lLiAKCkhlcmUgaXMgdGhlIGZpcnN0LCBhbmQgcHJpbWFyeSwgdmVyc2lvbjoKCmBgYHtyfQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBSdW4gdGhlIGZ1bGwgbW9kZWwgaW4gYSBjbHVzdGVyLiBUaGlzIHZlcnNpb24gd3JpdGVzIGZpbGVzIHRvIGEgY2x1c3RlciBvdXRwdXQgZm9sZGVyLgojIHJtKGxpc3QgPSBscygpKQojIGluc3RhbGwucGFja2FnZXMoIn4vRGVza3RvcC9GQVJNXzEuMC50YXIuZ3oiLCByZXBvcz1OVUxMLCB0eXBlPSJzb3VyY2UiKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyBuZWVkIHRvIGRvY3VtZW50IHdoaWNoIGZ1bmN0aW9ucyB3ZSB1c2UgZnJvbSBlYWNoIG9mIHRoZXNlIGxpYnJhcmllcy4gCmxpYnJhcnkoYXBlKQpsaWJyYXJ5KHNwZGVwKQpsaWJyYXJ5KFJjcHApCmxpYnJhcnkobXNtKQpsaWJyYXJ5KEZBUk0pCgoKc2ltX3J1bl9jbHVzdGVyIDwtIGZ1bmN0aW9uKHJlcGxpY2F0ZV9jeWNsZSwgbXlXb3JsZCwgbnVtYmVyX29mX3RpbWVfc3RlcHMsIG5icywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlcl9vZl90aXBzLCBudW1iZXJfb2ZfbmVpZ2hib3JzLCBvcmlnaW5zLCBzdGFydCA9IE5VTEwpIHsKICAjIENhbGxzIHRoZSBmdWxsIHNpbXVsYXRpb24gc2NyaXB0IAogICMJIAogICMgUHVycG9zZTogTmVlZCB0byB3cmFwIHRoZSBlbnRpcmUgc2ltdWxhdGlvbiBzY3JpcHQgaW50byBhIGZ1bmN0aW9uIHNvIGl0IGNhbiBiZSBjYWxsZWQgaW4gcGFyYWxsZWwgZnJvbSBhIGNsdXN0ZXIgY2FsbCAJCiAgIwogICMgQXJnczoKICAjICAgIHJlcGxpY2F0ZV9jeWNsZTogQW4gaW50ZWdlciBpbmRpY2F0aW5nIHRoZSByZXBsaWNhdGUgbnVtYmVyIG9mIGEgc2ltdWxhdGlvbi4gVGhpcyB2YXJpYWJsZSBpcyB1c2VkIGluIHRoaXMgZnVuY3Rpb24gdG8gbGFiZWwgICAgICAgIAogICMJCQl0aGUgc2F2ZWQgb3V0cHV0IGZpbGUgYW5kIGNvbnRyb2wgdGhlIG51bWJlciBvZiByZXBsaWNhdGVzIHJ1biBieSB0aGUgY2x1c3Rlci4KICAjCiAgIyAgICBjb21ib19udW1iZXI6IEFuIGludGVyZ2VyIGJldHdlZW4gMSBhbmQgMzEgaW5kaWNhdGluZyB0aGUgY29tYmluYXRpb25zIG9mIFMsIEUsIEEsIEQsIGFuZCBUIG1vZHVsZXMgdG8gYmUgaW5jbHVkZWQgCiAgIwkJCWluIHRoZSBzaW11bGF0aW9uLiBUaGUgZnVsbCBsaXN0IG9mIHRoZXNlIGNvbWJpbmF0aW9ucyBjYW4gYmUgcHJpbnRlZCB1c2luZyB0aGUgZnVuY3Rpb24gY29tYm9fb2ZfY2hvaWNlKDI4LCBUUlVFKS4KICAjIAkJV2UgYXJlIGN1cnJlbnRseSB1c2luZyBjb21iaW5hdGlvbnMgMjUsMjgsMjksYW5kIDMxIGFzIG91ciBmb3VyIGNvbXBldGluZyBtb2RlbHMgZm9yIHRoZSBzcHJlYWQgb2YgYWdyaWN1bHR1cmUuICAKICAjCiAgIyAgICBteVdvcmxkOiBNYXRyaXggdGhhdCBkZWZpbmVzIHRoZSBzY29wZSBvZiB0aGUgYXZhaWxhYmxlIHdvcmxkIGFuZCBhY3RzIGFzIGEgZGF0YSBodWIgZm9yIG9yZ2FuaXppbmcgYW5kIHJlcG9ydGluZyAJICAKICAjCQkJcmVzdWx0cyBmcm9tIHRoZSBkaWZmZXJlbnQgZWxlbWVudHMgb2YgdGhlIHNpbXVsYXRpb24uIAogICMKICAjICAgIG51bWJlcl9vZl90aW1lX3N0ZXBzOiBBbiBpbnRlZ2VyIGluZGljYXRpbmcgaG93IG1hbnkgaXRlcmF0aW9ucyB0aGUgc2ltdWxhdGlvbiB3aWxsIGNhbGN1bGF0ZWQgYmVmb3JlIHdyaXRpbmcgdGhlIGRhdGEgCiAgIwkJCWZpbGUuIAogICMKICAjICAgIG5iczogQSBsaXN0IG9mIHRoZSBhdmFpbGFibGUgbmVpZ2hib3JzIGZvciBlYWNoIHNwYXRpYWwgcG9pbnQuIFRoaXMgaXMgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgdGhlIGludGVyYWN0aW9uIAogICMJCQlvZiBuZWlnaGJvcnMgdGhyb3VnaCB0aW1lLiAKICAjCiAgIyAgICBudW1iZXJfb2ZfdGlwczogQW4gaW50ZXJnZXIgaW5kaWNhdGluZyB0aGUgbnVtYmVyIG9mIHRyZWUgdGlwcyB0aGUgc2ltdWxhdGlvbiBzaG91bGQgYmUgdHJ1bmNhdGVkIHRvLiBUaGUgZGVmYXVsdCBpcyB0byAKICAjCQkJaW5jbHVkZSBhbGwgdGhlIGF2YWlsYWJsZSB0aXBzIChlLmcuIDEyNTQgZm9yIGh1bWFuIGxhbmd1YWdlcykuIAogICMKICAjIFJldHVybnM6IAogICMgICAgbXlPdXQ6IEEgbGlzdCBvYmplY3QgY29udGFpbmluZyBhICdwaHlsbycgdHJlZSBvYmplY3QgY2FsbGVkIG15dHJlZSBpbiB0aGUgZmlyc3QgcG9zaXRpb24gYW5kIHRoZSBteVdvcmxkIG1hdHJpeCBvZiAKICAjICAgICAgCXNwYXRpYWwgYW5kIHRyZWUgZGF0YSBpbiB0aGUgc2Vjb25kIHBvc2l0aW9uIAogICMJCQogIAoKICB4MSA8LSA0ICNOdW1iZXIgb2YgcnVucyBwZXIgY29yZQogIHNhbXBsZWVyIDwtIHNhbXBsZShjKDEsMiw1LDYpLCB4MSkKICAjaWYgKHJlcGxpY2F0ZV9jeWNsZSAhPSAxKSB7CiAgIyAgcmVwbGljYXRlX2N5Y2xlIDwtICgocmVwbGljYXRlX2N5Y2xlIC0gMSkgKiB4MSkgKyAxCiAjIH0KICMgcmVwbGljYXRlX2N5Y2xlIDwtIHJlcGxpY2F0ZV9jeWNsZToocmVwbGljYXRlX2N5Y2xlICsgKHgxIC0gMSkpCiAgZm9yIChjb3VudCBpbiBzYW1wbGVlcikgewogIGluZGVwZW5kZW50IDwtIDEgCgogICAgCiAgICAjIFByb2JhYmlsaXR5IG9mIEFyaXNhbAogICAgcHJvYl9jaG9vc2VfYSA8LSByZXYoc29ydChyZXhwKDQsIHJhdGUgPSA5KSkpCiAgICBwcm9iX2Nob29zZV9hIDwtIHByb2JfY2hvb3NlX2FbYyhzYW1wbGUoMToyLCAyKSwgc2FtcGxlKDM6NCwgMikpXQogICAgcHJvYl9jaG9vc2VfYVszXSA8LSAwCiAgICBQLkFyaXNhbDAgIDwtIHBhcmFtZXRlcnMocHJvYl9jaG9vc2VfYVsxXSwgcHJvYl9jaG9vc2VfYVs0XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iX2Nob29zZV9hWzNdLCBwcm9iX2Nob29zZV9hWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFbnZfTm9uRCIsICJFbnZfRCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkV2b2xfdG9fRiIsICJFdm9sX3RvX0QiKQogICAgIyBQLkFyaXNhbDAgaXMgdGhlIG9uZSB5b3Ugc2hvdWxkIGNoYW5nZSB0aGUgcGFyYW1ldGVycwogICAgUC5BcmlzYWwgPC0gbWF0cml4KE5BLCBuY29sID0gMiwgbnJvdyA9IG5yb3cobXlXb3JsZCkpICMgcHJvYmFiaWxpdHkgcGVyIGNlbGwKICAgIGNvbG5hbWVzKFAuQXJpc2FsKSA8LSBjKCJFdm9sdmVfdG9fRiIsICJFdm9sdmVfdG9fRCIpCiAgICBFbnYuRG9tIDwtIG15V29ybGRbLCA3XSA9PSAyCiAgICBQLkFyaXNhbFtFbnYuRG9tLCAxXSA8LSBQLkFyaXNhbDBbMSwgMl0KICAgIFAuQXJpc2FsWyFFbnYuRG9tLCAxXSA8LSBQLkFyaXNhbDBbMSwgMV0KICAgIFAuQXJpc2FsW0Vudi5Eb20sIDJdIDwtIFAuQXJpc2FsMFsyLCAyXQogICAgUC5BcmlzYWxbIUVudi5Eb20sIDJdIDwtIFAuQXJpc2FsMFsyLCAxXQogICAgCiAgICBjb2xuYW1lcyhQLkFyaXNhbCkgPC0gYygiUHJvYl9vZl9Gb3JhZ2luZyIsICJQcm9iX29mX0RvbWVzdGljYXRpb24iKQogICAgUC5BcmlzYWxbd2hpY2gob3JpZ2lucyA9PSBGQUxTRSksIDJdICA8LSAwCiAgICAKICAgICMjIyMjCiAgICAjcHJvYl9jaG9vc2UgPC0gcnVuaWYoMTIsIDAuMDEsIDEpCiAgICAjc3ViIDwtIChwcm9iX2Nob29zZVsxXSAtIDAuMDEpCiAgICAjc3ViIDwtIGlmZWxzZShzdWIgPCAuMSwgLjEsIHN1YikKICAgICNwcm9iX2Nob29zZVtjKDQpXSA8LSBydW5pZigxLCAwLjAxLCBzdWIpCiAgICAjcHJvYl9jaG9vc2VbYyg1KV0gPC0gcnVuaWYoMSwgMC4xLCAxKSAjIEhpZ2ggZXh0aW5jdGlvbgogICAgI3Byb2JfY2hvb3NlW2MoNildIDwtIHJ1bmlmKDEsIDAsIChwcm9iX2Nob29zZVszXSAtIDAuMDEpKQogICAgI3Byb2JfY2hvb3NlW2MoOSwgMTAsIDEyKV0gPC0gcnVuaWYoMywgMC4wMSwgcHJvYl9jaG9vc2VbMTFdKQogICAgCiAgICAjIyMjCiAgICBwcm9iX2Nob29zZSA8LSBydW5pZigxMiwgMCwgMSkKICAgIHRvcCA8LSBtaW4ocHJvYl9jaG9vc2VbYygxLDMpXSwgbmEucm09VFJVRSkKICAgIHByb2JfY2hvb3NlW2MoMildIDwtIHJ1bmlmKDEsIDAsIHRvcCkKICAgIAogICAgcHJvYl9jaG9vc2VbYyg1KV0gPC0gcnVuaWYoMSwgMCwgcHJvYl9jaG9vc2VbYygyKV0pIAogICAgcHJvYl9jaG9vc2VbYyg2KV0gPC0gcnVuaWYoMSwgMCwgcHJvYl9jaG9vc2VbYyg1KV0pCiAgICBwcm9iX2Nob29zZVtjKDQpXSA8LSBydW5pZigxLCBwcm9iX2Nob29zZVtjKDYpXSwgcHJvYl9jaG9vc2VbYyg1KV0pCiAgICAKICAgICAgICAKICAgIGlmIChjb3VudCA9PSAxKSB7CiAgICAgIHByb2JfY2hvb3NlWzc6MTJdIDwtIDAKICAgIH0KICAgIGlmIChjb3VudCA9PSAyKSB7CiAgICAgIHByb2JfY2hvb3NlWzk6MTJdIDwtIDAKICAgIH0KICAgIGlmIChjb3VudCA9PSAzIHwgY291bnQgPT0gNSkgewogICAgICBwcm9iX2Nob29zZVs3OjhdIDwtIDAKICAgICAgaW5kZXBlbmRlbnQgPC0gMAogICAgfQogICAgaWYgKGNvdW50ID09IDQgfCBjb3VudCA9PSA2KSB7CiAgICAgIGluZGVwZW5kZW50IDwtIDAKICAgIH0KICAgIAogICAgCiAgICBQLnNwZWNpYXRpb24gPC0gcGFyYW1ldGVycyhwcm9iX2Nob29zZVsxXSwgcHJvYl9jaG9vc2VbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iX2Nob29zZVsyXSwgcHJvYl9jaG9vc2VbM10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRW52X05vbkQiLCAiRW52X0QiLCAiRm9yIiwgIkRvbSIpCgogICAgUC5leHRpbmN0aW9uICA8LSBwYXJhbWV0ZXJzKHByb2JfY2hvb3NlWzRdLCBwcm9iX2Nob29zZVs0XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iX2Nob29zZVs1XSwgcHJvYl9jaG9vc2VbNl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVudl9Ob25EIiwgIkVudl9EIiwgIkZvciIsICJEb20iKQoKICAgIAogICAgUC5kaWZmdXNpb24gPC0gcGFyYW1ldGVycygwLCBwcm9iX2Nob29zZVs3XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYl9jaG9vc2VbOF0sIDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUYXJnZXRfRm9yIiwgIlRhcmdldF9Eb20iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU291cmNlX0ZvciIsICJTb3VyY2VfRG9tIikKICAgIAogICAgUC5UYWtlT3ZlciA8LSBwYXJhbWV0ZXJzKHByb2JfY2hvb3NlWzldLCBwcm9iX2Nob29zZVsxMF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYl9jaG9vc2VbMTFdLCBwcm9iX2Nob29zZVsxMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRhcmdldF9Gb3IiLCAiVGFyZ2V0X0RvbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNvdXJjZV9Gb3IiLCAiU291cmNlX0RvbSIpCiAgICBtdWx0aXBsaWVyIDwtIDEgIyBhbHdheXMgMSBub3cuCiAgIGlmIChjb3VudCAlaW4lIDE6NCkgeyAKICAgIAlteU91dCA8LSBSdW5TaW1VbHRpbWF0ZShteVdvcmxkLCBQLmV4dGluY3Rpb24sIFAuc3BlY2lhdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBQLmRpZmZ1c2lvbiwgUC5BcmlzYWwsIFAuVGFrZU92ZXIsIG5icywgaW5kZXBlbmRlbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBOLnN0ZXBzID0gbnVtYmVyX29mX3RpbWVfc3RlcHMsIHNpbGVudCA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11bHRpcGxpZXIgPSBtdWx0aXBsaWVyLCBzdGFydCA9IHN0YXJ0KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICBpZiAoY291bnQgJWluJSA1OjYpIHsKICAgICAJbXlPdXQgPC0gUnVuU2ltVWx0aW1hdGUucHVzaChteVdvcmxkLCBQLmV4dGluY3Rpb24sIFAuc3BlY2lhdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBQLmRpZmZ1c2lvbiwgUC5BcmlzYWwsIFAuVGFrZU92ZXIsIG5icywgaW5kZXBlbmRlbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBOLnN0ZXBzID0gbnVtYmVyX29mX3RpbWVfc3RlcHMsIHNpbGVudCA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11bHRpcGxpZXIgPSBtdWx0aXBsaWVyLCBzdGFydCA9IHN0YXJ0KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICMgQ291bnQgcmVmZXJzIHRvIHRoZSBjb21ibywgMSA9IG51bGwsIDIgPSBkaWZmdXNpb24sIDMgPSBUYWtlb3ZlciwgNCA9IGZ1bGwKICAgIHNhdmUobXlPdXQsICBmaWxlPSBwYXN0ZTAoIi4vTW9kdWxlXzFfb3V0cHV0cy9teU91dF9yZXBfIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0QyhyZXBsaWNhdGVfY3ljbGUsIHdpZHRoID0gMixmbGFnID0gMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJfY29tYm9fIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0Qyhjb3VudCwgd2lkdGggPSAyLGZsYWcgPSAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIl8iLCJwYXJhbXMiLCAiX1Auc3BlY2lhdGlvbl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShmb3JtYXRDKFAuc3BlY2lhdGlvbiwgd2lkdGggPSAyLGZsYWcgPSAwKSwgY29sbGFwc2U9Il8iKSwiX1AuZXh0aW5jdF8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShmb3JtYXRDKFAuZXh0aW5jdGlvbiwgd2lkdGggPSAyLGZsYWcgPSAwKSwgY29sbGFwc2U9Il8iKSwgIl9QLmRpZmZ1c18iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShmb3JtYXRDKFAuZGlmZnVzaW9uLCB3aWR0aCA9IDIsZmxhZyA9IDApLCBjb2xsYXBzZT0iXyIpLCAiX1AuVE9fIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoZm9ybWF0QyhQLlRha2VPdmVyLCB3aWR0aCA9IDIsZmxhZyA9IDApLCBjb2xsYXBzZT0iXyIpLCJfUC5BcmlzYWxfIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoZm9ybWF0QyhQLkFyaXNhbDAsIHdpZHRoID0gMixmbGFnID0gMCksIGNvbGxhcHNlPSJfIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJfdGltZXN0ZXBzXyIsIG51bWJlcl9vZl90aW1lX3N0ZXBzLCAiX05CU18iLCBudW1iZXJfb2ZfbmVpZ2hib3JzLCAiXy5SZGF0YSIpKQoKICAgIFNpbV9zdGF0aXN0aWNzIDwtIE1vZHVsZV8yKG15T3V0KQoKICAgIHNhdmUoU2ltX3N0YXRpc3RpY3MsIGZpbGU9IHBhc3RlMCgiLi9Nb2R1bGVfMl9vdXRwdXRzL1NpbV9zdGF0c19yZXBfIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXRDKHJlcGxpY2F0ZV9jeWNsZSwgd2lkdGggPSAyLGZsYWcgPSAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiX2NvbWJvXyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0Qyhjb3VudCwgd2lkdGggPSAyLGZsYWcgPSAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXyIsInBhcmFtcyIsICJfUC5zcGVjaWF0aW9uXyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoZm9ybWF0QyhQLnNwZWNpYXRpb24sIHdpZHRoID0gMixmbGFnID0gMCksIGNvbGxhcHNlPSJfIiksIl9QLmV4dGluY3RfIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShmb3JtYXRDKFAuZXh0aW5jdGlvbiwgd2lkdGggPSAyLGZsYWcgPSAwKSwgY29sbGFwc2U9Il8iKSwgIl9QLmRpZmZ1c18iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKGZvcm1hdEMoUC5kaWZmdXNpb24sIHdpZHRoID0gMixmbGFnID0gMCksIGNvbGxhcHNlPSJfIiksICJfUC5UT18iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKGZvcm1hdEMoUC5UYWtlT3Zlciwgd2lkdGggPSAyLGZsYWcgPSAwKSwgY29sbGFwc2U9Il8iKSwiX1AuQXJpc2FsXyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoZm9ybWF0QyhQLkFyaXNhbDAsIHdpZHRoID0gMixmbGFnID0gMCksIGNvbGxhcHNlPSJfIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIl90aW1lc3RlcHNfIiwgbnVtYmVyX29mX3RpbWVfc3RlcHMsICJfTkJTXyIsIG51bWJlcl9vZl9uZWlnaGJvcnMsICJfLlJkYXRhIikpCiAgfQogIAp9CgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKY29vcmRzIDwtIGFzLm1hdHJpeChhcHBseShsYW5ndWFnZV9jZW50cm9pZHNbLCAzOjRdLCAyLCBhcy5udW1lcmljKSkgI2Nvb3Jkcwpjb25kcyA8LSBpZmVsc2Uoc3VpdGFiaWxpdHkyID09IDAsIDEsIDIpCmNvbmRzW2lzLm5hKGNvbmRzKV0gPC0gc2FtcGxlKGMoMSwgMiksIHN1bShpcy5uYShjb25kcykpLCByZXBsYWNlID0gVFJVRSkgCm9yaWdpbnMgPC0gbGFuZ3VhZ2VfY2VudHJvaWRzWywgNV0KCiMjIyMjIFNwZWNpZnkgc2ltdWxhdGlvbiBwYXJhbWV0ZXJzICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKbnVtYmVyX29mX3RpcHMgPC0gbGVuZ3RoKGNvb3Jkc1ssMV0pCm51bWJlcl9vZl90aW1lX3N0ZXBzX2EgPC0gMzAwMDAKI3JlcGxpY2F0ZV9jeWNsZSA8LSBjKDEpICAjbnVtYmVyIG9mIHJlcGxpY2F0ZXMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmRhdGEoInBhcmFtZXRlcnMudGFibGUiKQoKCnN5c3RlbS50aW1lKAogIG15V29ybGQgPC0gQnVpbGRXb3JsZChjb29yZHMsIGNvbmRzKQopCm51bWJlcl9vZl9uZWlnaGJvcnMgPC0gc2FtcGxlKDU6OSwxKQoKbmJzIDwtIGtubjJuYihrbmVhcm5laWdoKGNvb3JkcywgayA9IG51bWJlcl9vZl9uZWlnaGJvcnMsIGxvbmdsYXQgPSBUUlVFKSwKICAgICAgICAgICAgICBzeW0gPSBUUlVFKSAjIDcgc3ltbWV0cmljIG5laWdoYm9ycwpuLm9icyA8LSBzYXBwbHkobmJzLCBsZW5ndGgpCnNlcS5tYXggPC0gc2VxX2xlbihtYXgobi5vYnMpKQpuYnMgPC0gdChzYXBwbHkobmJzLCAiWyIsIGkgPSBzZXEubWF4KSkKCmRpbShteVdvcmxkKQoKCiMgTkFJIDwtIDEwMDAKYXJncyA8LSBjb21tYW5kQXJncyh0cmFpbGluZ09ubHkgPSBGQUxTRSkKcHJpbnQoYXJncykKTkFJIDwtIGFzLm51bWVyaWMoYXJnc1s3XSkKI3NldHdkKCJ+L0JveCBTeW5jL2NvbGxpZGluZyByYW5nZXMvU2ltdWxhdGlvbnNfaHVtYW5zL2JpZyB3b3JsZCBjbHVzdGVyIG91dHB1dHMiKQoKCiMgU3RhcnRpbmcgcG9pbnQKc3RhcnQgPC0gc2FtcGxlKCgxOm5yb3cobGFuZ3VhZ2VfY2VudHJvaWRzKSlbYXMubG9naWNhbChsYW5ndWFnZV9jZW50cm9pZHNbLCA2XSldLCAxKQoKI3NpbV9ydW5fY2x1c3RlcihyZXBsaWNhdGVfY3ljbGUgPSBOQUksCiMgICAgICAgICAgICAgICAgbXlXb3JsZCwgbnVtYmVyX29mX3RpbWVfc3RlcHMgPSBudW1iZXJfb2ZfdGltZV9zdGVwc19hLCAKIyAgICAgICAgICAgICAgICBuYnMsIG51bWJlcl9vZl90aXBzID0gbnJvdyhteVdvcmxkKSwgbnVtYmVyX29mX25laWdoYm9ycz0gbnVtYmVyX29mX25laWdoYm9ycywgI29yaWdpbnM9b3JpZ2lucyxzdGFydCA9IHN0YXJ0KQoKCgpgYGAKCgpIZXJlIGlzIHRoZSBzZWNvbmQgdmVyc2lvbgoKYGBge3J9CgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIFJ1biB0aGUgZnVsbCBtb2RlbCBpbiBhIGNsdXN0ZXIuIFRoaXMgdmVyc2lvbiB3cml0ZXMgZmlsZXMgdG8gYSBjbHVzdGVyIG91dHB1dCBmb2xkZXIuCiMgcm0obGlzdCA9IGxzKCkpCiMgaW5zdGFsbC5wYWNrYWdlcygifi9EZXNrdG9wL0ZBUk1fMS4wLnRhci5neiIsIHJlcG9zPU5VTEwsIHR5cGU9InNvdXJjZSIpCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIG5lZWQgdG8gZG9jdW1lbnQgd2hpY2ggZnVuY3Rpb25zIHdlIHVzZSBmcm9tIGVhY2ggb2YgdGhlc2UgbGlicmFyaWVzLiAKbGlicmFyeShhcGUpCmxpYnJhcnkoc3BkZXApCmxpYnJhcnkoUmNwcCkKbGlicmFyeShtc20pCmxpYnJhcnkoRkFSTSkKCgpzaW1fcnVuX2NsdXN0ZXIgPC0gZnVuY3Rpb24ocmVwbGljYXRlX2N5Y2xlLCBteVdvcmxkLCBudW1iZXJfb2ZfdGltZV9zdGVwcywgbmJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtYmVyX29mX3RpcHMsIG51bWJlcl9vZl9uZWlnaGJvcnMsIG9yaWdpbnMsIHN0YXJ0ID0gTlVMTCkgewogICMgQ2FsbHMgdGhlIGZ1bGwgc2ltdWxhdGlvbiBzY3JpcHQgCiAgIwkgCiAgIyBQdXJwb3NlOiBOZWVkIHRvIHdyYXAgdGhlIGVudGlyZSBzaW11bGF0aW9uIHNjcmlwdCBpbnRvIGEgZnVuY3Rpb24gc28gaXQgY2FuIGJlIGNhbGxlZCBpbiBwYXJhbGxlbCBmcm9tIGEgY2x1c3RlciBjYWxsIAkKICAjCiAgIyBBcmdzOgogICMgICAgcmVwbGljYXRlX2N5Y2xlOiBBbiBpbnRlZ2VyIGluZGljYXRpbmcgdGhlIHJlcGxpY2F0ZSBudW1iZXIgb2YgYSBzaW11bGF0aW9uLiBUaGlzIHZhcmlhYmxlIGlzIHVzZWQgaW4gdGhpcyBmdW5jdGlvbiB0byBsYWJlbCAgICAgICAgCiAgIwkJCXRoZSBzYXZlZCBvdXRwdXQgZmlsZSBhbmQgY29udHJvbCB0aGUgbnVtYmVyIG9mIHJlcGxpY2F0ZXMgcnVuIGJ5IHRoZSBjbHVzdGVyLgogICMKICAjICAgIGNvbWJvX251bWJlcjogQW4gaW50ZXJnZXIgYmV0d2VlbiAxIGFuZCAzMSBpbmRpY2F0aW5nIHRoZSBjb21iaW5hdGlvbnMgb2YgUywgRSwgQSwgRCwgYW5kIFQgbW9kdWxlcyB0byBiZSBpbmNsdWRlZCAKICAjCQkJaW4gdGhlIHNpbXVsYXRpb24uIFRoZSBmdWxsIGxpc3Qgb2YgdGhlc2UgY29tYmluYXRpb25zIGNhbiBiZSBwcmludGVkIHVzaW5nIHRoZSBmdW5jdGlvbiBjb21ib19vZl9jaG9pY2UoMjgsIFRSVUUpLgogICMgCQlXZSBhcmUgY3VycmVudGx5IHVzaW5nIGNvbWJpbmF0aW9ucyAyNSwyOCwyOSxhbmQgMzEgYXMgb3VyIGZvdXIgY29tcGV0aW5nIG1vZGVscyBmb3IgdGhlIHNwcmVhZCBvZiBhZ3JpY3VsdHVyZS4gIAogICMKICAjICAgIG15V29ybGQ6IE1hdHJpeCB0aGF0IGRlZmluZXMgdGhlIHNjb3BlIG9mIHRoZSBhdmFpbGFibGUgd29ybGQgYW5kIGFjdHMgYXMgYSBkYXRhIGh1YiBmb3Igb3JnYW5pemluZyBhbmQgcmVwb3J0aW5nIAkgIAogICMJCQlyZXN1bHRzIGZyb20gdGhlIGRpZmZlcmVudCBlbGVtZW50cyBvZiB0aGUgc2ltdWxhdGlvbi4gCiAgIwogICMgICAgbnVtYmVyX29mX3RpbWVfc3RlcHM6IEFuIGludGVnZXIgaW5kaWNhdGluZyBob3cgbWFueSBpdGVyYXRpb25zIHRoZSBzaW11bGF0aW9uIHdpbGwgY2FsY3VsYXRlZCBiZWZvcmUgd3JpdGluZyB0aGUgZGF0YSAKICAjCQkJZmlsZS4gCiAgIwogICMgICAgbmJzOiBBIGxpc3Qgb2YgdGhlIGF2YWlsYWJsZSBuZWlnaGJvcnMgZm9yIGVhY2ggc3BhdGlhbCBwb2ludC4gVGhpcyBpcyBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uIGZvciBjYWxjdWxhdGluZyB0aGUgaW50ZXJhY3Rpb24gCiAgIwkJCW9mIG5laWdoYm9ycyB0aHJvdWdoIHRpbWUuIAogICMKICAjICAgIG51bWJlcl9vZl90aXBzOiBBbiBpbnRlcmdlciBpbmRpY2F0aW5nIHRoZSBudW1iZXIgb2YgdHJlZSB0aXBzIHRoZSBzaW11bGF0aW9uIHNob3VsZCBiZSB0cnVuY2F0ZWQgdG8uIFRoZSBkZWZhdWx0IGlzIHRvIAogICMJCQlpbmNsdWRlIGFsbCB0aGUgYXZhaWxhYmxlIHRpcHMgKGUuZy4gMTI1NCBmb3IgaHVtYW4gbGFuZ3VhZ2VzKS4gCiAgIwogICMgUmV0dXJuczogCiAgIyAgICBteU91dDogQSBsaXN0IG9iamVjdCBjb250YWluaW5nIGEgJ3BoeWxvJyB0cmVlIG9iamVjdCBjYWxsZWQgbXl0cmVlIGluIHRoZSBmaXJzdCBwb3NpdGlvbiBhbmQgdGhlIG15V29ybGQgbWF0cml4IG9mIAogICMgICAgICAJc3BhdGlhbCBhbmQgdHJlZSBkYXRhIGluIHRoZSBzZWNvbmQgcG9zaXRpb24gCiAgIwkJCiAgCgogIHgxIDwtIDQgI051bWJlciBvZiBydW5zIHBlciBjb3JlCiAgc2FtcGxlZXIgPC0gc2FtcGxlKGMoMSwyLDUsNiksIHgxKQogICNpZiAocmVwbGljYXRlX2N5Y2xlICE9IDEpIHsKICAjICByZXBsaWNhdGVfY3ljbGUgPC0gKChyZXBsaWNhdGVfY3ljbGUgLSAxKSAqIHgxKSArIDEKICMgfQogIyByZXBsaWNhdGVfY3ljbGUgPC0gcmVwbGljYXRlX2N5Y2xlOihyZXBsaWNhdGVfY3ljbGUgKyAoeDEgLSAxKSkKICBmb3IgKGNvdW50IGluIHNhbXBsZWVyKSB7CiAgaW5kZXBlbmRlbnQgPC0gMSAKCiAgICAKICAgICMgUHJvYmFiaWxpdHkgb2YgQXJpc2FsCiAgICBwcm9iX2Nob29zZV9hIDwtIHJldihzb3J0KHJleHAoNCwgcmF0ZSA9IDkpKSkKICAgIHByb2JfY2hvb3NlX2EgPC0gcHJvYl9jaG9vc2VfYVtjKHNhbXBsZSgxOjIsIDIpLCBzYW1wbGUoMzo0LCAyKSldCiAgICBwcm9iX2Nob29zZV9hWzNdIDwtIDAKICAgIFAuQXJpc2FsMCAgPC0gcGFyYW1ldGVycyhwcm9iX2Nob29zZV9hWzFdLCBwcm9iX2Nob29zZV9hWzRdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2JfY2hvb3NlX2FbM10sIHByb2JfY2hvb3NlX2FbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVudl9Ob25EIiwgIkVudl9EIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRXZvbF90b19GIiwgIkV2b2xfdG9fRCIpCiAgICAjIFAuQXJpc2FsMCBpcyB0aGUgb25lIHlvdSBzaG91bGQgY2hhbmdlIHRoZSBwYXJhbWV0ZXJzCiAgICBQLkFyaXNhbCA8LSBtYXRyaXgoTkEsIG5jb2wgPSAyLCBucm93ID0gbnJvdyhteVdvcmxkKSkgIyBwcm9iYWJpbGl0eSBwZXIgY2VsbAogICAgY29sbmFtZXMoUC5BcmlzYWwpIDwtIGMoIkV2b2x2ZV90b19GIiwgIkV2b2x2ZV90b19EIikKICAgIEVudi5Eb20gPC0gbXlXb3JsZFssIDddID09IDIKICAgIFAuQXJpc2FsW0Vudi5Eb20sIDFdIDwtIFAuQXJpc2FsMFsxLCAyXQogICAgUC5BcmlzYWxbIUVudi5Eb20sIDFdIDwtIFAuQXJpc2FsMFsxLCAxXQogICAgUC5BcmlzYWxbRW52LkRvbSwgMl0gPC0gUC5BcmlzYWwwWzIsIDJdCiAgICBQLkFyaXNhbFshRW52LkRvbSwgMl0gPC0gUC5BcmlzYWwwWzIsIDFdCiAgICAKICAgIGNvbG5hbWVzKFAuQXJpc2FsKSA8LSBjKCJQcm9iX29mX0ZvcmFnaW5nIiwgIlByb2Jfb2ZfRG9tZXN0aWNhdGlvbiIpCiAgICBQLkFyaXNhbFt3aGljaChvcmlnaW5zID09IEZBTFNFKSwgMl0gIDwtIDAKICAgIAogICAgIyMjIyMKICAgICNwcm9iX2Nob29zZSA8LSBydW5pZigxMiwgMC4wMSwgMSkKICAgICNzdWIgPC0gKHByb2JfY2hvb3NlWzFdIC0gMC4wMSkKICAgICNzdWIgPC0gaWZlbHNlKHN1YiA8IC4xLCAuMSwgc3ViKQogICAgI3Byb2JfY2hvb3NlW2MoNCldIDwtIHJ1bmlmKDEsIDAuMDEsIHN1YikKICAgICNwcm9iX2Nob29zZVtjKDUpXSA8LSBydW5pZigxLCAwLjEsIDEpICMgSGlnaCBleHRpbmN0aW9uCiAgICAjcHJvYl9jaG9vc2VbYyg2KV0gPC0gcnVuaWYoMSwgMCwgKHByb2JfY2hvb3NlWzNdIC0gMC4wMSkpCiAgICAjcHJvYl9jaG9vc2VbYyg5LCAxMCwgMTIpXSA8LSBydW5pZigzLCAwLjAxLCBwcm9iX2Nob29zZVsxMV0pCiAgICAKICAgICMjIyMKICAgIHByb2JfY2hvb3NlIDwtIHJ1bmlmKDEyLCAwLCAxKQogICAgdG9wIDwtIG1pbihwcm9iX2Nob29zZVtjKDEsMyldLCBuYS5ybT1UUlVFKQogICAgcHJvYl9jaG9vc2VbYygyKV0gPC0gcnVuaWYoMSwgMCwgdG9wKQogICAgCiAgICBwcm9iX2Nob29zZVtjKDUpXSA8LSBydW5pZigxLCAwLCBwcm9iX2Nob29zZVtjKDIpXSkgCiAgICBwcm9iX2Nob29zZVtjKDYpXSA8LSBydW5pZigxLCAwLCBwcm9iX2Nob29zZVtjKDUpXSkKICAgIHByb2JfY2hvb3NlW2MoNCldIDwtIHJ1bmlmKDEsIHByb2JfY2hvb3NlW2MoNildLCBwcm9iX2Nob29zZVtjKDUpXSkKICAgIAogICAgICAgIAogICAgaWYgKGNvdW50ID09IDEpIHsKICAgICAgcHJvYl9jaG9vc2VbNzoxMl0gPC0gMAogICAgfQogICAgaWYgKGNvdW50ID09IDIpIHsKICAgICAgcHJvYl9jaG9vc2VbOToxMl0gPC0gMAogICAgfQogICAgaWYgKGNvdW50ID09IDMgfCBjb3VudCA9PSA1KSB7CiAgICAgIHByb2JfY2hvb3NlWzc6OF0gPC0gMAogICAgICBpbmRlcGVuZGVudCA8LSAwCiAgICB9CiAgICBpZiAoY291bnQgPT0gNCB8IGNvdW50ID09IDYpIHsKICAgICAgaW5kZXBlbmRlbnQgPC0gMAogICAgfQogICAgCiAgICAKICAgIFAuc3BlY2lhdGlvbiA8LSBwYXJhbWV0ZXJzKHByb2JfY2hvb3NlWzFdLCBwcm9iX2Nob29zZVsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2JfY2hvb3NlWzJdLCBwcm9iX2Nob29zZVszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFbnZfTm9uRCIsICJFbnZfRCIsICJGb3IiLCAiRG9tIikKCiAgICBQLmV4dGluY3Rpb24gIDwtIHBhcmFtZXRlcnMocHJvYl9jaG9vc2VbNF0sIHByb2JfY2hvb3NlWzRdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2JfY2hvb3NlWzVdLCBwcm9iX2Nob29zZVs2XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRW52X05vbkQiLCAiRW52X0QiLCAiRm9yIiwgIkRvbSIpCgogICAgCiAgICBQLmRpZmZ1c2lvbiA8LSBwYXJhbWV0ZXJzKDAsIHByb2JfY2hvb3NlWzddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iX2Nob29zZVs4XSwgMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRhcmdldF9Gb3IiLCAiVGFyZ2V0X0RvbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTb3VyY2VfRm9yIiwgIlNvdXJjZV9Eb20iKQogICAgCiAgICBQLlRha2VPdmVyIDwtIHBhcmFtZXRlcnMocHJvYl9jaG9vc2VbOV0sIHByb2JfY2hvb3NlWzEwXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iX2Nob29zZVsxMV0sIHByb2JfY2hvb3NlWzEyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGFyZ2V0X0ZvciIsICJUYXJnZXRfRG9tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU291cmNlX0ZvciIsICJTb3VyY2VfRG9tIikKICAgIG11bHRpcGxpZXIgPC0gMSAjIGFsd2F5cyAxIG5vdy4KICAgaWYgKGNvdW50ICVpbiUgMTo0KSB7IAogICAgCW15T3V0IDwtIFJ1blNpbVVsdGltYXRlMihteVdvcmxkLCBQLmV4dGluY3Rpb24sIFAuc3BlY2lhdGlvbiwgUC5kaWZmdXNpb24sIFAuQXJpc2FsLCAKICAgIFAuVGFrZU92ZXIsIG5icywgaW5kZXBlbmRlbnQsIG51bWJlcl9vZl90aW1lX3N0ZXBzLCBtdWx0aXBsaWVyLCBzaWxlbnQgPSBUUlVFLCAKICAgIGNvdW50LCByZXNvbHV0aW9uID0gc2VxKDEsIG51bWJlcl9vZl90aW1lX3N0ZXBzLCAxMDApLCBQLkFyaXNhbDAsIHN0YXJ0ID0gTlVMTCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgaWYgKGNvdW50ICVpbiUgNTo2KSB7CiAgICAgCW15T3V0IDwtIFJ1blNpbVVsdGltYXRlMi5wdXNoKG15V29ybGQsIFAuZXh0aW5jdGlvbiwgUC5zcGVjaWF0aW9uLCBQLmRpZmZ1c2lvbiwgUC5BcmlzYWwsIAogICAgUC5UYWtlT3ZlciwgbmJzLCBpbmRlcGVuZGVudCwgbnVtYmVyX29mX3RpbWVfc3RlcHMsIG11bHRpcGxpZXIsIHNpbGVudCA9IFRSVUUsIAogICAgY291bnQsIHJlc29sdXRpb24gPSBzZXEoMSwgbnVtYmVyX29mX3RpbWVfc3RlcHMsIDEwMCksIFAuQXJpc2FsMCwgc3RhcnQgPSBOVUxMKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIAogIH0KICAKfQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmNvb3JkcyA8LSBhcy5tYXRyaXgoYXBwbHkobGFuZ3VhZ2VfY2VudHJvaWRzWywgMzo0XSwgMiwgYXMubnVtZXJpYykpICNjb29yZHMKY29uZHMgPC0gaWZlbHNlKHN1aXRhYmlsaXR5MiA9PSAwLCAxLCAyKQpjb25kc1tpcy5uYShjb25kcyldIDwtIHNhbXBsZShjKDEsIDIpLCBzdW0oaXMubmEoY29uZHMpKSwgcmVwbGFjZSA9IFRSVUUpIApvcmlnaW5zIDwtIGxhbmd1YWdlX2NlbnRyb2lkc1ssIDVdCgojIyMjIyBTcGVjaWZ5IHNpbXVsYXRpb24gcGFyYW1ldGVycyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCm51bWJlcl9vZl90aXBzIDwtIGxlbmd0aChjb29yZHNbLDFdKQpudW1iZXJfb2ZfdGltZV9zdGVwc19hIDwtIDUwMDAwCiNyZXBsaWNhdGVfY3ljbGUgPC0gYygxKSAgI251bWJlciBvZiByZXBsaWNhdGVzCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpkYXRhKCJwYXJhbWV0ZXJzLnRhYmxlIikKCgpzeXN0ZW0udGltZSgKICBteVdvcmxkIDwtIEJ1aWxkV29ybGQoY29vcmRzLCBjb25kcykKKQpudW1iZXJfb2ZfbmVpZ2hib3JzIDwtIHNhbXBsZSg1OjksMSkKCm5icyA8LSBrbm4ybmIoa25lYXJuZWlnaChjb29yZHMsIGsgPSBudW1iZXJfb2ZfbmVpZ2hib3JzLCBsb25nbGF0ID0gVFJVRSksCiAgICAgICAgICAgICAgc3ltID0gVFJVRSkgIyA3IHN5bW1ldHJpYyBuZWlnaGJvcnMKbi5vYnMgPC0gc2FwcGx5KG5icywgbGVuZ3RoKQpzZXEubWF4IDwtIHNlcV9sZW4obWF4KG4ub2JzKSkKbmJzIDwtIHQoc2FwcGx5KG5icywgIlsiLCBpID0gc2VxLm1heCkpCgpkaW0obXlXb3JsZCkKCgojIE5BSSA8LSAxMDAwCmFyZ3MgPC0gY29tbWFuZEFyZ3ModHJhaWxpbmdPbmx5ID0gRkFMU0UpCnByaW50KGFyZ3MpCk5BSSA8LSBhcy5udW1lcmljKGFyZ3NbN10pCiNzZXR3ZCgifi9Cb3ggU3luYy9jb2xsaWRpbmcgcmFuZ2VzL1NpbXVsYXRpb25zX2h1bWFucy9iaWcgd29ybGQgY2x1c3RlciBvdXRwdXRzIikKCgojIFN0YXJ0aW5nIHBvaW50CnN0YXJ0IDwtIHNhbXBsZSgoMTpucm93KGxhbmd1YWdlX2NlbnRyb2lkcykpW2FzLmxvZ2ljYWwobGFuZ3VhZ2VfY2VudHJvaWRzWywgNl0pXSwgMSkKCiNzaW1fcnVuX2NsdXN0ZXIocmVwbGljYXRlX2N5Y2xlID0gTkFJLAojICAgICAgICAgICAgICAgIG15V29ybGQsIG51bWJlcl9vZl90aW1lX3N0ZXBzID0gbnVtYmVyX29mX3RpbWVfc3RlcHNfYSwgCiMgICAgICAgICAgICAgICAgbmJzLCBudW1iZXJfb2ZfdGlwcyA9IG5yb3cobXlXb3JsZCksIG51bWJlcl9vZl9uZWlnaGJvcnM9IG51bWJlcl9vZl9uZWlnaGJvcnMsIG9yaWdpbnM9b3JpZ2lucyxzdGFydCA9IHN0YXJ0KQoKCgpgYGAKCgoKCgoKCjwhLS1jaGFwdGVyOmVuZDpDYWxsX21vZHVsZXNfbWFzdGVyX3NjcmlwdF9tYXJrZG93bi5SbWQtLT4KCi0tLQp0aXRsZTogJ0QtcGxhY2UgRkFSTSBkb2N1bWVudGF0aW9uOiBGbG93IGNoYXJ0IG9mIGV4cGFuc2lvbiBydWxlcycKYXV0aG9yOiAiVHkgVHVmZiwgQnJ1bm8gVmlsZWxhLCBhbmQgQ2FybG9zIEJvdGVybyIKZGF0ZTogJ3Byb2plY3QgYmVnYW46IDE1IE1heSAyMDE2LCBkb2N1bWVudCB1cGRhdGVkOiBgciBzdHJmdGltZShTeXMudGltZSgpLCBmb3JtYXQKICA9ICIlZCAlQiAlWSIpYCcKb3V0cHV0OgogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgd29yZF9kb2N1bWVudDogZGVmYXVsdApiaWJsaW9ncmFwaHk6IEZBUk0gcGFja2FnZS5iaWIKLS0tCgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoIkRpYWdyYW1tZVIiKQpsaWJyYXJ5KERpYWdyYW1tZVIpCmBgYAoKCgoKYGBge3J9CgpnclZpeigiCiAgZGlncmFwaCB7CiAgICAKICAgIG5vZGUgW3NoYXBlID0gYm94CiAgICAgICAgICBmb250bmFtZSA9IEhlbHZldGljYQogICAgICAgICAgcGVud2lkdGggPSAyLjBdCiAgICAnSW5wdXQgdGhlIGRhdGEgaHViJzsgCiAgICAnSXMgdGhlcmUgbW9yZSB0aGFuIG9uZSBzb2NpZXQgaW4gdGhlIHdvcmxkPyc7IAogICAgJ1BpY2sgdGhlIG9ubHkgYXZhaWxhYmxlIHNvY2lldHknOwogICAgJ1JhbmRvbWx5IGNob29zIGEgc3ByZWFkZXIgc29jaWV0eSc7CiAgICAnQXJlIHRoZXJlIGFueSBlbXB0eSBuZWlnaGJvcmluZyBsb2NhdGlvbnM/JzsKICAgICdBdHRlbXB0IHRvIFRha292ZXInOwogICAgJ0lzIHRoZSBzcHJlYWRlciBhIEZvcmFnZXIgb2YgRG9tZXN0aWNhdG9yPyc7CiAgICAnaXMgdGhlcmUgbmVpZ2hib3JzIHdpdGggc3VpdGFibGUgZW5pdm9ucm1lbnQgZm9yIGRvbWVzdGljYXRpb24/JzsKICAgICdSYW5kb21seSBjaG9vc2UgYSB0YXJnZXQgbmVpZ2hib3InOwogICAgJ1JhbmRvbWx5IGNob29zZSBhIHRhcmV0IG5laWdoYm9yIGFtb25nIHRoZSBvbmVzIHdpdGggc3VpdGFibGUgY29uZGl0aW9uIGZvciBkb21lc3RpY2F0aW9uJzsKICAgICdSYW5kb21seSBjaG9vcyBhIG51bWJlciBiZXR3ZWVuIDAtMS4gSXMgdGhpcyBudW1iZXIgc21hbGxlciB0aGFuIHRoZSBwcm9iYWJpbGl0eSBvZiB0YWtlb3ZlciBmb3IgdGhlIGNvbmZpY3QgY2F0ZWdvcnkqKj8nOwogICAgJ1NwcmVhZGVyIHJlbW92ZXJzIHRhcmdldCBmcm9tIHRoZSBzcGFjZSBhbmQgcGh5bG9nZW55JzsKICAgICdOb3RoaW5nIGhhcHBlbnMnOwogICAgJ1NwZWFkZXIgb2NjdXBpZXMgdGhlIHRhcmdldCBjZWxsIGFuZCBiaWZ1cmNhdGUgaW4gdGhlIHBoeWxvZ2VueSc7CiAgICAnQXJlIHRoZXJlIGFueSBtb3JlIHNvY2lldGllcyByZW1haW5pbmcgKGV4Y2x1ZGluZyBuZXcgc29jaWV0aWVzIGdlbmVyYXRlZCBkdXJpbmcgdGhpcyBsb29wKSB0aGF0IGRpZCBub3QgZ28gdGhyb3VnaCB0aGUgZXhwYW5zaW9uIHByb2Nlc3M/JzsKICAgICdBdHRlbXB0IHRvIGRpc3BlcnNhbCc7CiAgICAnUmFuZG9tbHkgY2hvb3MgYW4gZW1wdHkgdGFyZ2V0IGxvY2F0aW9uJzsKICAgICdSYW5kb21seSBjaG9vcyBhIG51bWJlciBiZXR3ZWVuIDAtMS4gSXMgdGhpcyBudW1iZXIgc21hbGxlciB0aGFuIHRoZSBwcm9iYWJpbGl0eXkgb2Ygc3BlY2lhdGlvbiBmb3IgdGhlIHNwcmVhZGVyIHNvY2lldCB0cmFpdCBpbiB0aGUgcHJlPWV4cGFuZGluZyBsb2NhdGlvbiBlbnZpcm9ubWVudD8nOwogICAgJ291dHB1dCB0byBkYXRhIGh1Yic7CgogICAgZWRnZSBbXQogICAgJ0lucHV0IHRoZSBkYXRhIGh1YicgLT4gJ0lzIHRoZXJlIG1vcmUgdGhhbiBvbmUgc29jaWV0IGluIHRoZSB3b3JsZD8nOwogICAgJ0lzIHRoZXJlIG1vcmUgdGhhbiBvbmUgc29jaWV0IGluIHRoZSB3b3JsZD8nIC0+ICdQaWNrIHRoZSBvbmx5IGF2YWlsYWJsZSBzb2NpZXR5JyBbbGFiZWwgPSAnTk8nXTsKICAgICdJcyB0aGVyZSBtb3JlIHRoYW4gb25lIHNvY2lldCBpbiB0aGUgd29ybGQ/JyAtPiAnUmFuZG9tbHkgY2hvb3MgYSBzcHJlYWRlciBzb2NpZXR5JyBbbGFiZWwgPSAnWUVTJ107CiAgICAnUGljayB0aGUgb25seSBhdmFpbGFibGUgc29jaWV0eScgLT4gJ0FyZSB0aGVyZSBhbnkgZW1wdHkgbmVpZ2hib3JpbmcgbG9jYXRpb25zPyc7CiAgICAnUmFuZG9tbHkgY2hvb3MgYSBzcHJlYWRlciBzb2NpZXR5JyAtPiAnQXJlIHRoZXJlIGFueSBlbXB0eSBuZWlnaGJvcmluZyBsb2NhdGlvbnM/JzsKICAgICdBcmUgdGhlcmUgYW55IGVtcHR5IG5laWdoYm9yaW5nIGxvY2F0aW9ucz8nIC0+ICdBdHRlbXB0IHRvIGRpc3BlcnNhbCcgW2xhYmVsID0gJ1lFUyddOwogICAgJ0FyZSB0aGVyZSBhbnkgZW1wdHkgbmVpZ2hib3JpbmcgbG9jYXRpb25zPycgLT4gJ0F0dGVtcHQgdG8gVGFrb3ZlcicgW2xhYmVsID0gJ05PJ107CiAgICAnQXR0ZW1wdCB0byBUYWtvdmVyJyAtPiAnSXMgdGhlIHNwcmVhZGVyIGEgRm9yYWdlciBvZiBEb21lc3RpY2F0b3I/JzsKICAgICdJcyB0aGUgc3ByZWFkZXIgYSBGb3JhZ2VyIG9mIERvbWVzdGljYXRvcj8nIC0+ICdpcyB0aGVyZSBuZWlnaGJvcnMgd2l0aCBzdWl0YWJsZSBlbml2b25ybWVudCBmb3IgZG9tZXN0aWNhdGlvbj8nIFtsYWJlbCA9ICdEb21lc3RpY2F0b3InXTsKICAgICdJcyB0aGUgc3ByZWFkZXIgYSBGb3JhZ2VyIG9mIERvbWVzdGljYXRvcj8nIC0+ICdSYW5kb21seSBjaG9vc2UgYSB0YXJnZXQgbmVpZ2hib3InIFtsYWJlbCA9ICdGb3JhZ2VyJ107CiAgICAnaXMgdGhlcmUgbmVpZ2hib3JzIHdpdGggc3VpdGFibGUgZW5pdm9ucm1lbnQgZm9yIGRvbWVzdGljYXRpb24/JyAtPiAnUmFuZG9tbHkgY2hvb3NlIGEgdGFyZ2V0IG5laWdoYm9yJyBbbGFiZWwgPSAnTk8nXTsKICAgICdpcyB0aGVyZSBuZWlnaGJvcnMgd2l0aCBzdWl0YWJsZSBlbml2b25ybWVudCBmb3IgZG9tZXN0aWNhdGlvbj8nIC0+ICdSYW5kb21seSBjaG9vc2UgYSB0YXJldCBuZWlnaGJvciBhbW9uZyB0aGUgb25lcyB3aXRoIHN1aXRhYmxlIGNvbmRpdGlvbiBmb3IgZG9tZXN0aWNhdGlvbicgW2xhYmVsID0gJ1lFUyddOwogICAgJ1JhbmRvbWx5IGNob29zZSBhIHRhcmV0IG5laWdoYm9yIGFtb25nIHRoZSBvbmVzIHdpdGggc3VpdGFibGUgY29uZGl0aW9uIGZvciBkb21lc3RpY2F0aW9uJyAtPiAnUmFuZG9tbHkgY2hvb3MgYSBudW1iZXIgYmV0d2VlbiAwLTEuIElzIHRoaXMgbnVtYmVyIHNtYWxsZXIgdGhhbiB0aGUgcHJvYmFiaWxpdHkgb2YgdGFrZW92ZXIgZm9yIHRoZSBjb25maWN0IGNhdGVnb3J5Kio/JzsKICAgICdSYW5kb21seSBjaG9vc2UgYSB0YXJnZXQgbmVpZ2hib3InICAtPiAnUmFuZG9tbHkgY2hvb3MgYSBudW1iZXIgYmV0d2VlbiAwLTEuIElzIHRoaXMgbnVtYmVyIHNtYWxsZXIgdGhhbiB0aGUgcHJvYmFiaWxpdHkgb2YgdGFrZW92ZXIgZm9yIHRoZSBjb25maWN0IGNhdGVnb3J5Kio/JyA7CiAgICAnUmFuZG9tbHkgY2hvb3MgYSBudW1iZXIgYmV0d2VlbiAwLTEuIElzIHRoaXMgbnVtYmVyIHNtYWxsZXIgdGhhbiB0aGUgcHJvYmFiaWxpdHkgb2YgdGFrZW92ZXIgZm9yIHRoZSBjb25maWN0IGNhdGVnb3J5Kio/JyAtPiAnU3ByZWFkZXIgcmVtb3ZlcnMgdGFyZ2V0IGZyb20gdGhlIHNwYWNlIGFuZCBwaHlsb2dlbnknIFtsYWJlbCA9ICdZRVMnXTsKICAgICdSYW5kb21seSBjaG9vcyBhIG51bWJlciBiZXR3ZWVuIDAtMS4gSXMgdGhpcyBudW1iZXIgc21hbGxlciB0aGFuIHRoZSBwcm9iYWJpbGl0eSBvZiB0YWtlb3ZlciBmb3IgdGhlIGNvbmZpY3QgY2F0ZWdvcnkqKj8nIC0+ICdOb3RoaW5nIGhhcHBlbnMnIFtsYWJlbCA9ICdOTyddOwogICAgJ05vdGhpbmcgaGFwcGVucycgLT4gJ0FyZSB0aGVyZSBhbnkgbW9yZSBzb2NpZXRpZXMgcmVtYWluaW5nIChleGNsdWRpbmcgbmV3IHNvY2lldGllcyBnZW5lcmF0ZWQgZHVyaW5nIHRoaXMgbG9vcCkgdGhhdCBkaWQgbm90IGdvIHRocm91Z2ggdGhlIGV4cGFuc2lvbiBwcm9jZXNzPyc7CiAgICAnQXJlIHRoZXJlIGFueSBtb3JlIHNvY2lldGllcyByZW1haW5pbmcgKGV4Y2x1ZGluZyBuZXcgc29jaWV0aWVzIGdlbmVyYXRlZCBkdXJpbmcgdGhpcyBsb29wKSB0aGF0IGRpZCBub3QgZ28gdGhyb3VnaCB0aGUgZXhwYW5zaW9uIHByb2Nlc3M/JyAtPiAgJ291dHB1dCB0byBkYXRhIGh1YicgW2xhYmVsID0gJ05PJ107CiAgICAnQXR0ZW1wdCB0byBkaXNwZXJzYWwnIC0+ICdSYW5kb21seSBjaG9vcyBhbiBlbXB0eSB0YXJnZXQgbG9jYXRpb24nOwogICAgJ1JhbmRvbWx5IGNob29zIGFuIGVtcHR5IHRhcmdldCBsb2NhdGlvbicgLT4gJ1JhbmRvbWx5IGNob29zIGEgbnVtYmVyIGJldHdlZW4gMC0xLiBJcyB0aGlzIG51bWJlciBzbWFsbGVyIHRoYW4gdGhlIHByb2JhYmlsaXR5eSBvZiBzcGVjaWF0aW9uIGZvciB0aGUgc3ByZWFkZXIgc29jaWV0IHRyYWl0IGluIHRoZSBwcmU9ZXhwYW5kaW5nIGxvY2F0aW9uIGVudmlyb25tZW50Pyc7CiAgICAnUmFuZG9tbHkgY2hvb3MgYSBudW1iZXIgYmV0d2VlbiAwLTEuIElzIHRoaXMgbnVtYmVyIHNtYWxsZXIgdGhhbiB0aGUgcHJvYmFiaWxpdHl5IG9mIHNwZWNpYXRpb24gZm9yIHRoZSBzcHJlYWRlciBzb2NpZXQgdHJhaXQgaW4gdGhlIHByZT1leHBhbmRpbmcgbG9jYXRpb24gZW52aXJvbm1lbnQ/JyAtPiAnU3BlYWRlciBvY2N1cGllcyB0aGUgdGFyZ2V0IGNlbGwgYW5kIGJpZnVyY2F0ZSBpbiB0aGUgcGh5bG9nZW55JyBbbGFiZWwgPSAnWUVTJ107CiAgICAnUmFuZG9tbHkgY2hvb3MgYSBudW1iZXIgYmV0d2VlbiAwLTEuIElzIHRoaXMgbnVtYmVyIHNtYWxsZXIgdGhhbiB0aGUgcHJvYmFiaWxpdHl5IG9mIHNwZWNpYXRpb24gZm9yIHRoZSBzcHJlYWRlciBzb2NpZXQgdHJhaXQgaW4gdGhlIHByZT1leHBhbmRpbmcgbG9jYXRpb24gZW52aXJvbm1lbnQ/JyAtPiAnTm90aGluZyBoYXBwZW5zJyBbbGFiZWwgPSAnTk8nXTsKICAnQXJlIHRoZXJlIGFueSBtb3JlIHNvY2lldGllcyByZW1haW5pbmcgKGV4Y2x1ZGluZyBuZXcgc29jaWV0aWVzIGdlbmVyYXRlZCBkdXJpbmcgdGhpcyBsb29wKSB0aGF0IGRpZCBub3QgZ28gdGhyb3VnaCB0aGUgZXhwYW5zaW9uIHByb2Nlc3M/JyAtPiAgJ0lzIHRoZXJlIG1vcmUgdGhhbiBvbmUgc29jaWV0IGluIHRoZSB3b3JsZD8nIFtsYWJlbCA9ICdZRVMnXTsKICAnU3BlYWRlciBvY2N1cGllcyB0aGUgdGFyZ2V0IGNlbGwgYW5kIGJpZnVyY2F0ZSBpbiB0aGUgcGh5bG9nZW55JyAtPiAnQXJlIHRoZXJlIGFueSBtb3JlIHNvY2lldGllcyByZW1haW5pbmcgKGV4Y2x1ZGluZyBuZXcgc29jaWV0aWVzIGdlbmVyYXRlZCBkdXJpbmcgdGhpcyBsb29wKSB0aGF0IGRpZCBub3QgZ28gdGhyb3VnaCB0aGUgZXhwYW5zaW9uIHByb2Nlc3M/JzsKICAnU3ByZWFkZXIgcmVtb3ZlcnMgdGFyZ2V0IGZyb20gdGhlIHNwYWNlIGFuZCBwaHlsb2dlbnknIC0+ICdTcGVhZGVyIG9jY3VwaWVzIHRoZSB0YXJnZXQgY2VsbCBhbmQgYmlmdXJjYXRlIGluIHRoZSBwaHlsb2dlbnknOwogIH0iKQoKCgoKCgpgYGAKCgo8IS0tY2hhcHRlcjplbmQ6Rmxvd19jaGFydHMuUm1kLS0+CgotLS0KdGl0bGU6ICJELXBsYWNlIEZBUk0gZG9jdW1lbnRhdGlvbjogTW9kdWxlIDEiCmF1dGhvcjogIlR5IFR1ZmYsIEJydW5vIFZpbGVsYSwgYW5kIENhcmxvcyBCb3Rlcm8iCmRhdGU6ICdwcm9qZWN0IGJlZ2FuOiAxNSBNYXkgMjAxNiwgZG9jdW1lbnQgdXBkYXRlZDogYHIgc3RyZnRpbWUoU3lzLnRpbWUoKSwgZm9ybWF0CiAgPSAiJWQgJUIgJVkiKWAnCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKYmlibGlvZ3JhcGh5OiBGQVJNIHBhY2thZ2UuYmliCi0tLQoKIyBNb2R1bGUgMTogU2ltdWxhdGlvbiB0byBwcm9kdWNlIGEgd29ybGQgYW5kIGEgdHJlZSAKCmBgYHtyfQojIEluc3RhbGwgdGhlIG1vc3QgcmVjZW50IHZlcnNpb24gb2YgRkFSTSBmcm9tIGEgLnppcCBmaWxlCmluc3RhbGwucGFja2FnZXMoZmlsZS5jaG9vc2UoKSwgcmVwb3M9TlVMTCkgCmBgYAoKYGBge3J9CmxpYnJhcnkoRkFSTSkKbHMoInBhY2thZ2U6RkFSTSIpCmBgYAoKIyMgSW5wdXRzCiAKYGBge3J9CgpgYGAKCgojIyBNb2R1bGUgMSBmdW5jdGlvbnMKIyMjIyBUaGUgZmlyc3Qgc2V0IG9mIFJ1blNpbSBmdW5jdGlvbnMgYXJlIHRoZSBkZWZhdWx0IHBpcGVsaW5lIHdoZXJlIG9ubHkgb25lIG91dHB1dCBpcyBzYXZlZCBhdCB0aGUgZW5kIG9mIHRoZSBzaW11bGF0aW9uLiAKCgpUaGlzIGZpcnN0IGZ1bmN0aW9uIGNvbnRyb2xzIGVycm9yIG1lc3NhZ2VzIGNvbWluZyBmcm9tIHRoZSBwcmltYXJ5IGZ1bmN0aW9uIGJlbG93LiAKYGBge3J9CiMgUnVuIHRoZSBzaW11bGF0aW9uIGZ1bmN0aW9uIHNraXBpbmcgdGhlIGVycm9zIGFuZCBhdHJpYnV0aW5nIE5BIGlmIGl0IG9jY3VycwpSdW5TaW1VbHRpbWF0ZSA8LSBmdW5jdGlvbihteVdvcmxkLCBQLmV4dGluY3Rpb24sIFAuc3BlY2lhdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgUC5kaWZmdXNpb24sIFAuQXJpc2FsLCBQLlRha2VPdmVyLCBuYnMsIGluZGVwZW5kZW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICBOLnN0ZXBzLCBtdWx0aXBsaWVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzaWxlbnQgPSBUUlVFLCBzdGFydCA9IE5VTEwpIHsKCiAgcmVzdWx0IDwtIHRyeShSdW5TaW0obXlXb3JsZCwgUC5leHRpbmN0aW9uLCBQLnNwZWNpYXRpb24sCiAgICAgICAgICAgICAgICAgICAgICAgUC5kaWZmdXNpb24sIFAuQXJpc2FsLCBQLlRha2VPdmVyLCBuYnMsCiAgICAgICAgICAgICAgICAgICAgICAgaW5kZXBlbmRlbnQsIE4uc3RlcHMsCiAgICAgICAgICAgICAgICAgICAgICAgbXVsdGlwbGllciwgc3RhcnQgPSBzdGFydCksIHNpbGVudCA9IHNpbGVudCkKICBpZiAoY2xhc3MocmVzdWx0KSA9PSAidHJ5LWVycm9yIikgewogICAgcmVzdWx0IDwtIE5BCiAgfQogIHJldHVybihyZXN1bHQpCn0KCmBgYAoKVGhpcyBpcyB0aGUgcHJpbWFyeSBmdW5jdGlvbiBydW5uaW5nIHRoZSBzaW11bGF0aW9uLgpgYGB7cn0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIFNpbXVsYXRpb25GdW5jdGlvbnMuUgojCiMgQ29udGFpbnMgYSBmdW5jdGlvbiBmb3Igc2ltdWxhdGlvbiBvZiBjdWx0dXJhbCBldm9sdXRpb24gaW4gc3BhY2UgYW5kIHRpbWUKIyBBbGxvd3MgZm9yICgxKSBWZXJ0aWNhbCBUcmFuc21pc3Npb24gKHBoeWxvZ2VuZXRpYyBpbmhlcml0YW5jZSk7ICgyKSBIb3Jpem9udGFsCiMgVHJhbnNtaXNzaW9uIChjdWx0dXJhbCBkaWZmdXNpb24pOyAoMykgRWNvbG9naWNhbCBzZWxlY3Rpb24gKEJvdGggc3BlY2lhdGlvbiBhbmQKIyBleHRpbmN0aW9uIGFyZSBkZXRlcm1pbmVkIGJ5IHRoZSBtYXRjaCBiZXR3ZWVuIHRoZSBzdGF0ZSBvZiBhIGJpbmFyeSB0cmFpdCBhbmQgdGhlCiMgZW52aXJvbm1lbnQgYSBzb2NpZXR1eSBvY2N1cGllcykuCiMKIyA3IEp1biAyMDE2CiMgQ2FybG9zIEEuIEJvdGVybywgQnJ1bm8gVmlsZWxhICYgVHkgVHVmZgojIFdhc2hpbmd0b24gVW5pdmVyc2l0eSBpbiBTYWludCBMb3VpcwojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ClJ1blNpbSA8LSBmdW5jdGlvbihteVdvcmxkLCBQLmV4dGluY3Rpb24sIFAuc3BlY2lhdGlvbiwKICAgICAgICAgICAgICAgICAgIFAuZGlmZnVzaW9uLCBQLkFyaXNhbCwgUC5UYWtlT3ZlciwgbmJzLCBpbmRlcGVuZGVudCwKICAgICAgICAgICAgICAgICAgIE4uc3RlcHMsIG11bHRpcGxpZXIsIHN0YXJ0KSB7CiAgIyBteVdvcmxkID0gVGhlIGhleGFnb25hbCB3b3JsZCBjcmVhdGVkIHdpdGggdGhlIGZ1bmN0aW9uIEJ1aWxkV29ybGQKICAjIFAuZXh0aW5jdGlvbiA9IFByb2JhYmlsaXR5IG1hdHJpeCBvZiBleHRpbmN0aW9uCiAgIyBQLnNwZWNpYXRpb24gPSBQcm9iYWJpbGl0eSBtYXRyaXggb2Ygc3BlY2lhdGlvbgogICMgUC5kaWZmdXNpb24gPSBQcm9iYWJpbGl0eSBtYXRyaXggb2YgZGlmZnVzaW9uCiAgIyBQLkFyaXNhbCA9IFByb2JhYmlsaXR5IG1hdHJpeCBvZiBhcmlzYWwKICAjIFAuVGFrZU92ZXIgPSBQcm9iYWJpbGl0eSBtYXRyaXggb2YgdGFrZW92ZXIKICAjIE4uc3RlcHMgPSBOdW1iZXIgb2Ygc3RlcHMgaW4gdGhlIG1vZGVsCiAgIyBtdWx0aXBsaWVyID0gVGhlIG51bWJlciB0aGF0IHdpbGwgbXVsdGlwbHkgdGhlIHByb2JhYmlsaXRpZXMgYWNjb3JkaW5nCiAgIyB0byBlbnZpcm9ubWV0YWwgZml0bmVzcy4KICAjIHN0YXJ0ID0gdGhlIHBvaW50IElEIGluICdteVdvcmxkJyB0aGF0IHdpbGwgZ2l2ZSByaXNlbiB0byBodW1hbnMuCiAgIyAoaHVtYW5zIG9yaWdpbiB3aWxsIGJlIGluIG9uZSBvZiB0aGUgZXhpc3RpbmcgcG9zaXRpb25zKQoKICB3b3JsZC5zaXplIDwtIG5yb3cobXlXb3JsZCkKICAjIEluaXRpYWxpemUgcGFyYW1ldGVycyB3ZSB3aWxsIHVzZSBsYXRlciB0byBidWlsZCB0aGUgcGh5bG9nZW55CiAgcm9vdG5vZGUgPC0gIHdvcmxkLnNpemUgKyAxICMgc3RhbmRhcmQgY29udmVudGlvbiBmb3Igcm9vdCBub2RlIG51bWJlcgoKICAjIHNldCB0aGUgc2VlZCBmb3Igc2ltdWxhdGlvbgogIGlmIChpcy5udWxsKHN0YXJ0KSkgewogIHN0YXJ0IDwtIHNhbXBsZSgxOndvcmxkLnNpemUsIDEpCiAgfQoKICBteVdvcmxkW3N0YXJ0LCA0OjZdIDwtIGMoMCwgMCwgMSkgIyBTZXR0aW5nIHJvb3QoMCksIHRpbWUoMCksIGFuY2VzdHJhbCgxLCBmb3JhZ2VyKQoKICBteXRyZWUgPC0gVGhlT3JpZ2luT2ZTcGVjaWVzKHdvcmxkLnNpemUsIHN0YXJ0KSAjIEVtcHR5IHRyZWUKICBteVQgPC0gMCAjIFRpbWUgc3RhcnRzIGF0IHplcm8KCiAgIyBDb21tb24gaW5wdXQgYW5kIG91dHB1dCBmb3IgYWxsIHRoZSBpbnRlcm5hbCBtb2R1bGVzCiAgaW5wdXQgPC0gbGlzdChQLnNwZWNpYXRpb24sIFAuQXJpc2FsLCBQLmRpZmZ1c2lvbiwgUC5leHRpbmN0aW9uLCBQLlRha2VPdmVyLAogICAgICAgICAgICAgICAgbXlXb3JsZCwgbXl0cmVlLCBteVQsIG11bHRpcGxpZXIsIG5icywgaW5kZXBlbmRlbnQpCgogICMgRnVuY3Rpb25zIG9yZGVyIHRvIGJlIHJhbmRvbWl6ZWQKICByYW5kX29yZGVyX2Z1bmNfcnVuIDwtIGxpc3QoIkV4dGluY3Rpb24iLCAiRGlmZnVzaW9uIiwgIlNwZWNpYXRpb25UYWtlT3ZlciIsICJBcmlzYWwiKQoKICBjYXQoIjAlIFsiKSAjIFRpbWUgY291bnQKCiAgZm9yIChzdGVwcyBpbiAxOk4uc3RlcHMpIHsgIyBTdGFydHMgdGhlIGxvb3Agd2l0aCAnbicgc3RlcHMKCiAgICBpZiAoc3RlcHMgJSUgcm91bmQoKE4uc3RlcHMgLyAxMCkpID09IDApIHsgIyBUaW1lIGNvdW50CiAgICAgIGNhdCgnLScpICMgVGltZSBjb3VudAogICAgfSMgVGltZSBjb3VudAogICAgaWYgKHN0ZXBzID09IE4uc3RlcHMpIHsgIyBUaW1lIGNvdW50CiAgICAgIGNhdCgiXSAxMDAgJVxuIikjIFRpbWUgY291bnQKICAgIH0jIFRpbWUgY291bnQKCiAgICAjIFJhbmRvbWl6ZSBmdW5jdGlvbnMgb3JkZXIKICAgIHJhbmRfb3JkZXIgPC0gc2FtcGxlKHJhbmRfb3JkZXJfZnVuY19ydW4pCiAgICAjIFJ1biB0aGUgZnVuY3Rpb25zCiAgICBpbnB1dCA8LSBkby5jYWxsKHJhbmRfb3JkZXJbWzFdXSwgbGlzdChpbnB1dCA9IGlucHV0KSkKICAgIGlucHV0IDwtIGRvLmNhbGwocmFuZF9vcmRlcltbMl1dLCBsaXN0KGlucHV0ID0gaW5wdXQpKQogICAgaW5wdXQgPC0gZG8uY2FsbChyYW5kX29yZGVyW1szXV0sIGxpc3QoaW5wdXQgPSBpbnB1dCkpCiAgICBpbnB1dCA8LSBkby5jYWxsKHJhbmRfb3JkZXJbWzRdXSwgbGlzdChpbnB1dCA9IGlucHV0KSkKCiAgfQogICMgVHJ1bnNmb3JtIHRoZSBpbnB1dC9vdXRwdXQgaW50byB0aGUgZmluYWwgcmVzdWx0IGFuZCByZXR1cm4gaXQKICBteVdvcmxkIDwtIGFzLmRhdGEuZnJhbWUoaW5wdXRbWzZdXSkKICBteVdvcmxkWywgOF0gPC0gcGFzdGUwKCJ0IiwgbXlXb3JsZFssIDhdKQogIG15dHJlZSA8LSBtYWtlUGh5KGlucHV0W1s3XV0pCiAgbXl0cmVlJGVkZ2UubGVuZ3RoIDwtIG15dHJlZSRlZGdlLmxlbmd0aCAvIE4uc3RlcHMKICByZXR1cm4obGlzdCgnbXl0cmVlJyA9IG15dHJlZSwgJ215V29ybGQnID0gbXlXb3JsZCkpCn0KCmBgYAoKCgoKCgojUHVzaCB2ZXJzaW9ucyAKCmBgYHtyfQojIFJ1biB0aGUgc2ltdWxhdGlvbiBmdW5jdGlvbiBza2lwaW5nIHRoZSBlcnJvcyBhbmQgYXRyaWJ1dGluZyBOQSBpZiBpdCBvY2N1cnMKUnVuU2ltVWx0aW1hdGUucHVzaCA8LSBmdW5jdGlvbihteVdvcmxkLCBQLmV4dGluY3Rpb24sIFAuc3BlY2lhdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQLmRpZmZ1c2lvbiwgUC5BcmlzYWwsIFAuVGFrZU92ZXIsIG5icywgaW5kZXBlbmRlbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTi5zdGVwcywgbXVsdGlwbGllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWxlbnQgPSBUUlVFLCBzdGFydCA9IE5VTEwpIHsKCiAgcmVzdWx0IDwtIHRyeShSdW5TaW0ucHVzaChteVdvcmxkLCBQLmV4dGluY3Rpb24sIFAuc3BlY2lhdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFAuZGlmZnVzaW9uLCBQLkFyaXNhbCwgUC5UYWtlT3ZlciwgbmJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXBlbmRlbnQsIE4uc3RlcHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdWx0aXBsaWVyLCBzdGFydCA9IHN0YXJ0KSwgc2lsZW50ID0gc2lsZW50KQogIGlmIChjbGFzcyhyZXN1bHQpID09ICJ0cnktZXJyb3IiKSB7CiAgICByZXN1bHQgPC0gTkEKICB9CiAgcmV0dXJuKHJlc3VsdCkKfQoKCmBgYAoKCgoKCmBgYHtyfQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgU2ltdWxhdGlvbkZ1bmN0aW9ucy5SCiMKIyBDb250YWlucyBhIGZ1bmN0aW9uIGZvciBzaW11bGF0aW9uIG9mIGN1bHR1cmFsIGV2b2x1dGlvbiBpbiBzcGFjZSBhbmQgdGltZQojIEFsbG93cyBmb3IgKDEpIFZlcnRpY2FsIFRyYW5zbWlzc2lvbiAocGh5bG9nZW5ldGljIGluaGVyaXRhbmNlKTsgKDIpIEhvcml6b250YWwKIyBUcmFuc21pc3Npb24gKGN1bHR1cmFsIGRpZmZ1c2lvbik7ICgzKSBFY29sb2dpY2FsIHNlbGVjdGlvbiAoQm90aCBzcGVjaWF0aW9uIGFuZAojIGV4dGluY3Rpb24gYXJlIGRldGVybWluZWQgYnkgdGhlIG1hdGNoIGJldHdlZW4gdGhlIHN0YXRlIG9mIGEgYmluYXJ5IHRyYWl0IGFuZCB0aGUKIyBlbnZpcm9ubWVudCBhIHNvY2lldHV5IG9jY3VwaWVzKS4KIwojIDcgSnVuIDIwMTYKIyBDYXJsb3MgQS4gQm90ZXJvLCBCcnVubyBWaWxlbGEgJiBUeSBUdWZmCiMgV2FzaGluZ3RvbiBVbml2ZXJzaXR5IGluIFNhaW50IExvdWlzCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KUnVuU2ltLnB1c2ggPC0gZnVuY3Rpb24obXlXb3JsZCwgUC5leHRpbmN0aW9uLCBQLnNwZWNpYXRpb24sCiAgICAgICAgICAgICAgICAgICBQLmRpZmZ1c2lvbiwgUC5BcmlzYWwsIFAuVGFrZU92ZXIsIG5icywgaW5kZXBlbmRlbnQsCiAgICAgICAgICAgICAgICAgICBOLnN0ZXBzLCBtdWx0aXBsaWVyLCBzdGFydCkgewogICMgbXlXb3JsZCA9IFRoZSBoZXhhZ29uYWwgd29ybGQgY3JlYXRlZCB3aXRoIHRoZSBmdW5jdGlvbiBCdWlsZFdvcmxkCiAgIyBQLmV4dGluY3Rpb24gPSBQcm9iYWJpbGl0eSBtYXRyaXggb2YgZXh0aW5jdGlvbgogICMgUC5zcGVjaWF0aW9uID0gUHJvYmFiaWxpdHkgbWF0cml4IG9mIHNwZWNpYXRpb24KICAjIFAuZGlmZnVzaW9uID0gUHJvYmFiaWxpdHkgbWF0cml4IG9mIGRpZmZ1c2lvbgogICMgUC5BcmlzYWwgPSBQcm9iYWJpbGl0eSBtYXRyaXggb2YgYXJpc2FsCiAgIyBQLlRha2VPdmVyID0gUHJvYmFiaWxpdHkgbWF0cml4IG9mIHRha2VvdmVyCiAgIyBOLnN0ZXBzID0gTnVtYmVyIG9mIHN0ZXBzIGluIHRoZSBtb2RlbAogICMgbXVsdGlwbGllciA9IFRoZSBudW1iZXIgdGhhdCB3aWxsIG11bHRpcGx5IHRoZSBwcm9iYWJpbGl0aWVzIGFjY29yZGluZwogICMgdG8gZW52aXJvbm1ldGFsIGZpdG5lc3MuCiAgIyBzdGFydCA9IHRoZSBwb2ludCBJRCBpbiAnbXlXb3JsZCcgdGhhdCB3aWxsIGdpdmUgcmlzZW4gdG8gaHVtYW5zLgogICMgKGh1bWFucyBvcmlnaW4gd2lsbCBiZSBpbiBvbmUgb2YgdGhlIGV4aXN0aW5nIHBvc2l0aW9ucykKCiAgd29ybGQuc2l6ZSA8LSBucm93KG15V29ybGQpCiAgIyBJbml0aWFsaXplIHBhcmFtZXRlcnMgd2Ugd2lsbCB1c2UgbGF0ZXIgdG8gYnVpbGQgdGhlIHBoeWxvZ2VueQogIHJvb3Rub2RlIDwtICB3b3JsZC5zaXplICsgMSAjIHN0YW5kYXJkIGNvbnZlbnRpb24gZm9yIHJvb3Qgbm9kZSBudW1iZXIKCiAgIyBzZXQgdGhlIHNlZWQgZm9yIHNpbXVsYXRpb24KICBpZiAoaXMubnVsbChzdGFydCkpIHsKICAgIHN0YXJ0IDwtIHNhbXBsZSgxOndvcmxkLnNpemUsIDEpCiAgfQoKICBteVdvcmxkW3N0YXJ0LCA0OjZdIDwtIGMoMCwgMCwgMSkgIyBTZXR0aW5nIHJvb3QoMCksIHRpbWUoMCksIGFuY2VzdHJhbCgxLCBmb3JhZ2VyKQoKICBteXRyZWUgPC0gVGhlT3JpZ2luT2ZTcGVjaWVzKHdvcmxkLnNpemUsIHN0YXJ0KSAjIEVtcHR5IHRyZWUKICBteVQgPC0gMCAjIFRpbWUgc3RhcnRzIGF0IHplcm8KCiAgIyBDb21tb24gaW5wdXQgYW5kIG91dHB1dCBmb3IgYWxsIHRoZSBpbnRlcm5hbCBtb2R1bGVzCiAgaW5wdXQgPC0gbGlzdChQLnNwZWNpYXRpb24sIFAuQXJpc2FsLCBQLmRpZmZ1c2lvbiwgUC5leHRpbmN0aW9uLCBQLlRha2VPdmVyLAogICAgICAgICAgICAgICAgbXlXb3JsZCwgbXl0cmVlLCBteVQsIG11bHRpcGxpZXIsIG5icywgaW5kZXBlbmRlbnQpCgogICMgRnVuY3Rpb25zIG9yZGVyIHRvIGJlIHJhbmRvbWl6ZWQKICByYW5kX29yZGVyX2Z1bmNfcnVuIDwtIGxpc3QoIkV4dGluY3Rpb24iLCAiRGlmZnVzaW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNwZWNpYXRpb25UYWtlT3Zlci5wdXNoIiwgIkFyaXNhbCIpCgogIGNhdCgiMCUgWyIpICMgVGltZSBjb3VudAoKICBmb3IgKHN0ZXBzIGluIDE6Ti5zdGVwcykgeyAjIFN0YXJ0cyB0aGUgbG9vcCB3aXRoICduJyBzdGVwcwoKICAgIGlmIChzdGVwcyAlJSByb3VuZCgoTi5zdGVwcyAvIDEwKSkgPT0gMCkgeyAjIFRpbWUgY291bnQKICAgICAgY2F0KCctJykgIyBUaW1lIGNvdW50CiAgICB9IyBUaW1lIGNvdW50CiAgICBpZiAoc3RlcHMgPT0gTi5zdGVwcykgeyAjIFRpbWUgY291bnQKICAgICAgY2F0KCJdIDEwMCAlXG4iKSMgVGltZSBjb3VudAogICAgfSMgVGltZSBjb3VudAoKICAgICMgUmFuZG9taXplIGZ1bmN0aW9ucyBvcmRlcgogICAgcmFuZF9vcmRlciA8LSBzYW1wbGUocmFuZF9vcmRlcl9mdW5jX3J1bikKICAgICMgUnVuIHRoZSBmdW5jdGlvbnMKICAgIGlucHV0IDwtIGRvLmNhbGwocmFuZF9vcmRlcltbMV1dLCBsaXN0KGlucHV0ID0gaW5wdXQpKQogICAgaW5wdXQgPC0gZG8uY2FsbChyYW5kX29yZGVyW1syXV0sIGxpc3QoaW5wdXQgPSBpbnB1dCkpCiAgICBpbnB1dCA8LSBkby5jYWxsKHJhbmRfb3JkZXJbWzNdXSwgbGlzdChpbnB1dCA9IGlucHV0KSkKICAgIGlucHV0IDwtIGRvLmNhbGwocmFuZF9vcmRlcltbNF1dLCBsaXN0KGlucHV0ID0gaW5wdXQpKQoKICB9CiAgIyBUcnVuc2Zvcm0gdGhlIGlucHV0L291dHB1dCBpbnRvIHRoZSBmaW5hbCByZXN1bHQgYW5kIHJldHVybiBpdAogIG15V29ybGQgPC0gYXMuZGF0YS5mcmFtZShpbnB1dFtbNl1dKQogIG15V29ybGRbLCA4XSA8LSBwYXN0ZTAoInQiLCBteVdvcmxkWywgOF0pCiAgbXl0cmVlIDwtIG1ha2VQaHkoaW5wdXRbWzddXSkKICBteXRyZWUkZWRnZS5sZW5ndGggPC0gbXl0cmVlJGVkZ2UubGVuZ3RoIC8gTi5zdGVwcwogIHJldHVybihsaXN0KCdteXRyZWUnID0gbXl0cmVlLCAnbXlXb3JsZCcgPSBteVdvcmxkKSkKfQoKYGBgCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCiMjIyMgVGhlIHNlY29uZCBzZXQgb2YgUnVuU2ltIGZ1bmN0aW9ucyBzYXZlIGFuIG91dHB1dCBlYWNoIHRpbWVzdGVwIGlmIHdlIHdhbnQgdG8gbG9vayBhdCB0cmVuZHMgdGhyb3VnaCB0aW1lLiBXZSB1c2UgdGhpcyB0byBtYWtlIHZpZGVvcyBvZiB0aGUgc2ltdWxhdGlvbiBydW5uaW5nLiAKYGBge3J9ClJ1blNpbVVsdGltYXRlMiA8LSBmdW5jdGlvbiAobXlXb3JsZCwgUC5leHRpbmN0aW9uLCBQLnNwZWNpYXRpb24sIFAuZGlmZnVzaW9uLCBQLkFyaXNhbCwgCiAgICBQLlRha2VPdmVyLCBuYnMsIGluZGVwZW5kZW50LCBOLnN0ZXBzLCBtdWx0aXBsaWVyLCBzaWxlbnQgPSBUUlVFLCAKICAgIGNvdW50LCByZXNvbHV0aW9uID0gc2VxKDEsIE4uc3RlcHMsIDEwMCksIFAuQXJpc2FsMCwgc3RhcnQgPSBOVUxMKSAKewogICAgcmVzdWx0IDwtIHRyeShSdW5TaW0yKG15V29ybGQsIFAuZXh0aW5jdGlvbiwgUC5zcGVjaWF0aW9uLCAKICAgICAgICBQLmRpZmZ1c2lvbiwgUC5BcmlzYWwsIFAuVGFrZU92ZXIsIG5icywgaW5kZXBlbmRlbnQsIAogICAgICAgIE4uc3RlcHMsIG11bHRpcGxpZXIsIGNvdW50ID0gY291bnQsIHJlc29sdXRpb24gPSByZXNvbHV0aW9uLCAKICAgICAgICBQLkFyaXNhbDAgPSBQLkFyaXNhbDAsIHN0YXJ0KSwgc2lsZW50ID0gc2lsZW50KQogICAgaWYgKGNsYXNzKHJlc3VsdCkgPT0gInRyeS1lcnJvciIpIHsKICAgICAgICByZXN1bHQgPC0gTkEKICAgIH0KICAgIHJldHVybihyZXN1bHQpCn0KYGBgCgoKYGBge3J9ClJ1blNpbTIgPC0gZnVuY3Rpb24gKG15V29ybGQsIFAuZXh0aW5jdGlvbiwgUC5zcGVjaWF0aW9uLCBQLmRpZmZ1c2lvbiwgUC5BcmlzYWwsIAogICAgUC5UYWtlT3ZlciwgbmJzLCBpbmRlcGVuZGVudCwgTi5zdGVwcywgbXVsdGlwbGllciwgY291bnQsIAogICAgcmVzb2x1dGlvbiwgUC5BcmlzYWwwLCBzdGFydCA9IE5VTEwpIAp7CiAgICBmb2xkZXIgPC0gcGFzdGUwKCIuL01vZHVsZV8xX291dHB1dHMvbXlPdXRfcmVwXyIsIGZvcm1hdEMoY291bnQsIAogICAgICAgIHdpZHRoID0gMiwgZmxhZyA9IDApLCAiX2NvbWJvXyIsIGZvcm1hdEMoY291bnQsIHdpZHRoID0gMiwgCiAgICAgICAgZmxhZyA9IDApLCAiXyIsICJwYXJhbXMiLCAiX1Auc3BlY2lhdGlvbl8iLCBwYXN0ZShmb3JtYXRDKFAuc3BlY2lhdGlvbiwgCiAgICAgICAgd2lkdGggPSAyLCBmbGFnID0gMCksIGNvbGxhcHNlID0gIl8iKSwgIl9QLmV4dGluY3Rpb25fIiwgCiAgICAgICAgcGFzdGUoZm9ybWF0QyhQLmV4dGluY3Rpb24sIHdpZHRoID0gMiwgZmxhZyA9IDApLCBjb2xsYXBzZSA9ICJfIiksIAogICAgICAgICJfUC5kaWZmdXNpb25fIiwgcGFzdGUoZm9ybWF0QyhQLmRpZmZ1c2lvbiwgd2lkdGggPSAyLCAKICAgICAgICAgICAgZmxhZyA9IDApLCBjb2xsYXBzZSA9ICJfIiksICJfUC5UT18iLCBwYXN0ZShmb3JtYXRDKFAuVGFrZU92ZXIsIAogICAgICAgICAgICB3aWR0aCA9IDIsIGZsYWcgPSAwKSwgY29sbGFwc2UgPSAiXyIpLCAiX1AuQXJpc2FsXyIsIAogICAgICAgIHBhc3RlKGZvcm1hdEMoUC5BcmlzYWwwLCB3aWR0aCA9IDIsIGZsYWcgPSAwKSwgY29sbGFwc2UgPSAiXyIpLCAKICAgICAgICAiX3RpbWVzdGVwc18iLCBOLnN0ZXBzKQogICAgd29ybGQuc2l6ZSA8LSBucm93KG15V29ybGQpCiAgICByb290bm9kZSA8LSB3b3JsZC5zaXplICsgMQogICAgaWYgKGlzLm51bGwoc3RhcnQpKSB7CiAgICAgICAgc3RhcnQgPC0gc2FtcGxlKDE6d29ybGQuc2l6ZSwgMSkKICAgIH0KICAgIG15V29ybGRbc3RhcnQsIDQ6Nl0gPC0gYygwLCAwLCAxKQogICAgbXl0cmVlIDwtIFRoZU9yaWdpbk9mU3BlY2llcyh3b3JsZC5zaXplLCBzdGFydCkKICAgIG15VCA8LSAwCiAgICBpbnB1dCA8LSBsaXN0KFAuc3BlY2lhdGlvbiwgUC5BcmlzYWwsIFAuZGlmZnVzaW9uLCBQLmV4dGluY3Rpb24sIAogICAgICAgIFAuVGFrZU92ZXIsIG15V29ybGQsIG15dHJlZSwgbXlULCBtdWx0aXBsaWVyLCBuYnMsIGluZGVwZW5kZW50KQogICAgcmFuZF9vcmRlcl9mdW5jX3J1biA8LSBsaXN0KCJFeHRpbmN0aW9uIiwgIkRpZmZ1c2lvbiIsICJTcGVjaWF0aW9uVGFrZU92ZXIiLCAKICAgICAgICAiQXJpc2FsIikKICAgIGNhdCgiMCUgWyIpCiAgICBmb3IgKHN0ZXBzIGluIDE6Ti5zdGVwcykgewogICAgICAgIGlmIChzdGVwcyUlcm91bmQoKE4uc3RlcHMvMTApKSA9PSAwKSB7CiAgICAgICAgICAgIGNhdCgiLSIpCiAgICAgICAgfQogICAgICAgIGlmIChzdGVwcyA9PSBOLnN0ZXBzKSB7CiAgICAgICAgICAgIGNhdCgiXSAxMDAgJVxuIikKICAgICAgICB9CiAgICAgICAgcmFuZF9vcmRlciA8LSBzYW1wbGUocmFuZF9vcmRlcl9mdW5jX3J1bikKICAgICAgICBpbnB1dCA8LSBkby5jYWxsKHJhbmRfb3JkZXJbWzFdXSwgbGlzdChpbnB1dCA9IGlucHV0KSkKICAgICAgICBpbnB1dCA8LSBkby5jYWxsKHJhbmRfb3JkZXJbWzJdXSwgbGlzdChpbnB1dCA9IGlucHV0KSkKICAgICAgICBpbnB1dCA8LSBkby5jYWxsKHJhbmRfb3JkZXJbWzNdXSwgbGlzdChpbnB1dCA9IGlucHV0KSkKICAgICAgICBpbnB1dCA8LSBkby5jYWxsKHJhbmRfb3JkZXJbWzRdXSwgbGlzdChpbnB1dCA9IGlucHV0KSkKICAgICAgICBpZiAoc3RlcHMgJWluJSByZXNvbHV0aW9uKSB7CiAgICAgICAgICAgIG15V29ybGQgPC0gYXMuZGF0YS5mcmFtZShpbnB1dFtbNl1dKQogICAgICAgICAgICBteVdvcmxkWywgOF0gPC0gcGFzdGUwKCJ0IiwgbXlXb3JsZFssIDhdKQogICAgICAgICAgICBpZiAobnJvdyhuYS5vbWl0KGlucHV0W1s3XV0pKSA+IDEpIHsKICAgICAgICAgICAgICAgIG15dHJlZSA8LSBtYWtlUGh5KGlucHV0W1s3XV0pCiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICBteXRyZWUgPC0gTkEKICAgICAgICAgICAgfQogICAgICAgICAgICBteU91dCA8LSBsaXN0KG15dHJlZSA9IG15dHJlZSwgbXlXb3JsZCA9IG15V29ybGQpCiAgICAgICAgICAgIHNhdmUobXlPdXQsIGZpbGUgPSBwYXN0ZTAoZm9sZGVyLCAiXyIsIGZvcm1hdEMoc3RlcHMsIAogICAgICAgICAgICAgICAgMTAsIGZsYWcgPSAwKSwgIi5SZGF0YSIpKQogICAgICAgICAgICBzdGF0cyA8LSBNb2R1bGVfMihteU91dCkKICAgICAgICAgICAgc2F2ZShzdGF0cywgZmlsZSA9IHBhc3RlMChmb2xkZXIsICJfIiwgZm9ybWF0QyhzdGVwcywgCiAgICAgICAgICAgICAgICAxMCwgZmxhZyA9IDApLCAiX3N0YXRzIiwgIi5SZGF0YSIpKQogICAgICAgIH0KICAgIH0KICAgIG15V29ybGQgPC0gYXMuZGF0YS5mcmFtZShpbnB1dFtbNl1dKQogICAgbXlXb3JsZFssIDhdIDwtIHBhc3RlMCgidCIsIG15V29ybGRbLCA4XSkKICAgIG15dHJlZSA8LSBtYWtlUGh5KGlucHV0W1s3XV0pCiAgICBteXRyZWUkZWRnZS5sZW5ndGggPC0gbXl0cmVlJGVkZ2UubGVuZ3RoL04uc3RlcHMKICAgIHJldHVybihsaXN0KG15dHJlZSA9IG15dHJlZSwgbXlXb3JsZCA9IG15V29ybGQpKQp9CmBgYAoKCiMuLkFuZCB0aGUgcHVzaCB2ZXJzaW9uIG9mIHNhdmluZyBlYWNoIHRpbWUgc3RlcAoKCmBgYHtyfQojIFJ1biB0aGUgc2ltdWxhdGlvbiBmdW5jdGlvbiBza2lwaW5nIHRoZSBlcnJvcyBhbmQgYXRyaWJ1dGluZyBOQSBpZiBpdCBvY2N1cnMKUnVuU2ltVWx0aW1hdGUyLnB1c2ggPC0gZnVuY3Rpb24obXlXb3JsZCwgUC5leHRpbmN0aW9uLCBQLnNwZWNpYXRpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBQLmRpZmZ1c2lvbiwgUC5BcmlzYWwsIFAuVGFrZU92ZXIsIG5icywgaW5kZXBlbmRlbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBOLnN0ZXBzLCBtdWx0aXBsaWVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lsZW50ID0gVFJVRSwgY291bnQsIHJlc29sdXRpb24gPSBzZXEoMSwgTi5zdGVwcywgMTAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFAuQXJpc2FsMCwgc3RhcnQgPSBOVUxMKSB7CgogIHJlc3VsdCA8LSB0cnkoUnVuU2ltMi5wdXNoKG15V29ybGQsIFAuZXh0aW5jdGlvbiwgUC5zcGVjaWF0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICBQLmRpZmZ1c2lvbiwgUC5BcmlzYWwsIFAuVGFrZU92ZXIsIG5icywKICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXBlbmRlbnQsIE4uc3RlcHMsCiAgICAgICAgICAgICAgICAgICAgICAgIG11bHRpcGxpZXIsIGNvdW50ID0gY291bnQsIHJlc29sdXRpb24gPSByZXNvbHV0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICBQLkFyaXNhbDAgPSBQLkFyaXNhbDAsIHN0YXJ0KSwKICAgICAgICAgICAgICAgIHNpbGVudCA9IHNpbGVudCkKICBpZiAoY2xhc3MocmVzdWx0KSA9PSAidHJ5LWVycm9yIikgewogICAgcmVzdWx0IDwtIE5BCiAgfQogIHJldHVybihyZXN1bHQpCn0KCmBgYAoKCmBgYHtyfQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ClJ1blNpbTIucHVzaCA8LSBmdW5jdGlvbihteVdvcmxkLCBQLmV4dGluY3Rpb24sIFAuc3BlY2lhdGlvbiwKICAgICAgICAgICAgICAgICAgICBQLmRpZmZ1c2lvbiwgUC5BcmlzYWwsIFAuVGFrZU92ZXIsIG5icywgaW5kZXBlbmRlbnQsCiAgICAgICAgICAgICAgICAgICAgTi5zdGVwcywgbXVsdGlwbGllciwgY291bnQsIHJlc29sdXRpb24sIFAuQXJpc2FsMCwKICAgICAgICAgICAgICAgICAgICBzdGFydCA9IE5VTEwpIHsKICAjIG15V29ybGQgPSBUaGUgaGV4YWdvbmFsIHdvcmxkIGNyZWF0ZWQgd2l0aCB0aGUgZnVuY3Rpb24gQnVpbGRXb3JsZAogICMgUC5leHRpbmN0aW9uID0gUHJvYmFiaWxpdHkgbWF0cml4IG9mIGV4dGluY3Rpb24KICAjIFAuc3BlY2lhdGlvbiA9IFByb2JhYmlsaXR5IG1hdHJpeCBvZiBzcGVjaWF0aW9uCiAgIyBQLmRpZmZ1c2lvbiA9IFByb2JhYmlsaXR5IG1hdHJpeCBvZiBkaWZmdXNpb24KICAjIFAuQXJpc2FsID0gUHJvYmFiaWxpdHkgbWF0cml4IG9mIGFyaXNhbAogICMgUC5UYWtlT3ZlciA9IFByb2JhYmlsaXR5IG1hdHJpeCBvZiB0YWtlb3ZlcgogICMgTi5zdGVwcyA9IE51bWJlciBvZiBzdGVwcyBpbiB0aGUgbW9kZWwKICAjIG11bHRpcGxpZXIgPSBUaGUgbnVtYmVyIHRoYXQgd2lsbCBtdWx0aXBseSB0aGUgcHJvYmFiaWxpdGllcyBhY2NvcmRpbmcKICAjIHRvIGVudmlyb25tZXRhbCBmaXRuZXNzLgogICMgc3RhcnQgPSB0aGUgcG9pbnQgSUQgaW4gJ215V29ybGQnIHRoYXQgd2lsbCBnaXZlIHJpc2VuIHRvIGh1bWFucy4KICAjIChodW1hbnMgb3JpZ2luIHdpbGwgYmUgaW4gb25lIG9mIHRoZSBleGlzdGluZyBwb3NpdGlvbnMpCiAgZm9sZGVyIDwtIHBhc3RlMCgiLi9Nb2R1bGVfMV9vdXRwdXRzL215T3V0X3JlcF8iLAogICAgICAgICAgICAgICAgICAgZm9ybWF0Qyhjb3VudCwgd2lkdGggPSAyLGZsYWcgPSAwKSwKICAgICAgICAgICAgICAgICAgICJfY29tYm9fIiwKICAgICAgICAgICAgICAgICAgIGZvcm1hdEMoY291bnQsIHdpZHRoID0gMixmbGFnID0gMCksCiAgICAgICAgICAgICAgICAgICAiXyIsInBhcmFtcyIsICJfUC5zcGVjaWF0aW9uXyIsCiAgICAgICAgICAgICAgICAgICBwYXN0ZShmb3JtYXRDKFAuc3BlY2lhdGlvbiwgd2lkdGggPSAyLGZsYWcgPSAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlPSJfIiksIl9QLmV4dGluY3Rpb25fIiwKICAgICAgICAgICAgICAgICAgIHBhc3RlKGZvcm1hdEMoUC5leHRpbmN0aW9uLCB3aWR0aCA9IDIsZmxhZyA9IDApLAogICAgICAgICAgICAgICAgICAgICAgICAgY29sbGFwc2U9Il8iKSwgIl9QLmRpZmZ1c2lvbl8iLAogICAgICAgICAgICAgICAgICAgcGFzdGUoZm9ybWF0QyhQLmRpZmZ1c2lvbiwgd2lkdGggPSAyLGZsYWcgPSAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlPSJfIiksICJfUC5UT18iLAogICAgICAgICAgICAgICAgICAgcGFzdGUoZm9ybWF0QyhQLlRha2VPdmVyLCB3aWR0aCA9IDIsZmxhZyA9IDApLAogICAgICAgICAgICAgICAgICAgICAgICAgY29sbGFwc2U9Il8iKSwiX1AuQXJpc2FsXyIsCiAgICAgICAgICAgICAgICAgICBwYXN0ZShmb3JtYXRDKFAuQXJpc2FsMCwgd2lkdGggPSAyLGZsYWcgPSAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlPSJfIiksICJfdGltZXN0ZXBzXyIsCiAgICAgICAgICAgICAgICAgICBOLnN0ZXBzKQogIHdvcmxkLnNpemUgPC0gbnJvdyhteVdvcmxkKQogICMgSW5pdGlhbGl6ZSBwYXJhbWV0ZXJzIHdlIHdpbGwgdXNlIGxhdGVyIHRvIGJ1aWxkIHRoZSBwaHlsb2dlbnkKICByb290bm9kZSA8LSAgd29ybGQuc2l6ZSArIDEgIyBzdGFuZGFyZCBjb252ZW50aW9uIGZvciByb290IG5vZGUgbnVtYmVyCgogICMgc2V0IHRoZSBzZWVkIGZvciBzaW11bGF0aW9uCiAgaWYgKGlzLm51bGwoc3RhcnQpKSB7CiAgICBzdGFydCA8LSBzYW1wbGUoMTp3b3JsZC5zaXplLCAxKQogIH0KCiAgbXlXb3JsZFtzdGFydCwgNDo2XSA8LSBjKDAsIDAsIDEpICMgU2V0dGluZyByb290KDApLCB0aW1lKDApLCBhbmNlc3RyYWwoMSwgZm9yYWdlcikKCiAgbXl0cmVlIDwtIFRoZU9yaWdpbk9mU3BlY2llcyh3b3JsZC5zaXplLCBzdGFydCkgIyBFbXB0eSB0cmVlCiAgbXlUIDwtIDAgIyBUaW1lIHN0YXJ0cyBhdCB6ZXJvCgogICMgQ29tbW9uIGlucHV0IGFuZCBvdXRwdXQgZm9yIGFsbCB0aGUgaW50ZXJuYWwgbW9kdWxlcwogIGlucHV0IDwtIGxpc3QoUC5zcGVjaWF0aW9uLCBQLkFyaXNhbCwgUC5kaWZmdXNpb24sIFAuZXh0aW5jdGlvbiwgUC5UYWtlT3ZlciwKICAgICAgICAgICAgICAgIG15V29ybGQsIG15dHJlZSwgbXlULCBtdWx0aXBsaWVyLCBuYnMsIGluZGVwZW5kZW50KQoKICAjIEZ1bmN0aW9ucyBvcmRlciB0byBiZSByYW5kb21pemVkCiAgcmFuZF9vcmRlcl9mdW5jX3J1biA8LSBsaXN0KCJFeHRpbmN0aW9uIiwgIkRpZmZ1c2lvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTcGVjaWF0aW9uVGFrZU92ZXIucHVzaCIsICJBcmlzYWwiKQoKICBjYXQoIjAlIFsiKSAjIFRpbWUgY291bnQKCiAgZm9yIChzdGVwcyBpbiAxOk4uc3RlcHMpIHsgIyBTdGFydHMgdGhlIGxvb3Agd2l0aCAnbicgc3RlcHMKCiAgICBpZiAoc3RlcHMgJSUgcm91bmQoKE4uc3RlcHMgLyAxMCkpID09IDApIHsgIyBUaW1lIGNvdW50CiAgICAgIGNhdCgnLScpICMgVGltZSBjb3VudAogICAgfSMgVGltZSBjb3VudAogICAgaWYgKHN0ZXBzID09IE4uc3RlcHMpIHsgIyBUaW1lIGNvdW50CiAgICAgIGNhdCgiXSAxMDAgJVxuIikjIFRpbWUgY291bnQKICAgIH0jIFRpbWUgY291bnQKCiAgICAjIFJhbmRvbWl6ZSBmdW5jdGlvbnMgb3JkZXIKICAgIHJhbmRfb3JkZXIgPC0gc2FtcGxlKHJhbmRfb3JkZXJfZnVuY19ydW4pCiAgICAjIFJ1biB0aGUgZnVuY3Rpb25zCiAgICBpbnB1dCA8LSBkby5jYWxsKHJhbmRfb3JkZXJbWzFdXSwgbGlzdChpbnB1dCA9IGlucHV0KSkKICAgIGlucHV0IDwtIGRvLmNhbGwocmFuZF9vcmRlcltbMl1dLCBsaXN0KGlucHV0ID0gaW5wdXQpKQogICAgaW5wdXQgPC0gZG8uY2FsbChyYW5kX29yZGVyW1szXV0sIGxpc3QoaW5wdXQgPSBpbnB1dCkpCiAgICBpbnB1dCA8LSBkby5jYWxsKHJhbmRfb3JkZXJbWzRdXSwgbGlzdChpbnB1dCA9IGlucHV0KSkKICAgICMgU2F2ZQogICAgaWYoc3RlcHMgJWluJSByZXNvbHV0aW9uKSB7CiAgICAgIG15V29ybGQgPC0gYXMuZGF0YS5mcmFtZShpbnB1dFtbNl1dKQogICAgICBteVdvcmxkWywgOF0gPC0gcGFzdGUwKCJ0IiwgbXlXb3JsZFssIDhdKQogICAgICBpZihucm93KG5hLm9taXQoaW5wdXRbWzddXSkpID4gMSkgewogICAgICAgIG15dHJlZSA8LSBtYWtlUGh5KGlucHV0W1s3XV0pCiAgICAgIH0gZWxzZSB7CiAgICAgICAgbXl0cmVlIDwtIE5BCiAgICAgIH0KICAgICAgbXlPdXQgPC0gbGlzdCgnbXl0cmVlJyA9IG15dHJlZSwgJ215V29ybGQnID0gbXlXb3JsZCkKICAgICAgc2F2ZShteU91dCwgZmlsZT0gcGFzdGUwKGZvbGRlciwiXyIsIGZvcm1hdEMoc3RlcHMsIDEwLCBmbGFnID0gMCksICIuUmRhdGEiKSkKICAgICAgc3RhdHMgPC0gTW9kdWxlXzIobXlPdXQpCiAgICAgIHNhdmUoc3RhdHMsIGZpbGU9IHBhc3RlMChmb2xkZXIsIl8iLCBmb3JtYXRDKHN0ZXBzLCAxMCwgZmxhZyA9IDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIl9zdGF0cyIsICIuUmRhdGEiKSkKICAgIH0KICB9CiAgIyBUcnVuc2Zvcm0gdGhlIGlucHV0L291dHB1dCBpbnRvIHRoZSBmaW5hbCByZXN1bHQgYW5kIHJldHVybiBpdAogIG15V29ybGQgPC0gYXMuZGF0YS5mcmFtZShpbnB1dFtbNl1dKQogIG15V29ybGRbLCA4XSA8LSBwYXN0ZTAoInQiLCBteVdvcmxkWywgOF0pCiAgbXl0cmVlIDwtIG1ha2VQaHkoaW5wdXRbWzddXSkKICBteXRyZWUkZWRnZS5sZW5ndGggPC0gbXl0cmVlJGVkZ2UubGVuZ3RoIC8gTi5zdGVwcwogIHJldHVybihsaXN0KCdteXRyZWUnID0gbXl0cmVlLCAnbXlXb3JsZCcgPSBteVdvcmxkKSkKfQoKCmBgYAoKCgoKCgo8IS0tY2hhcHRlcjplbmQ6TW9kdWxlXzFfbWFya2Rvd24uUm1kLS0+CgotLS0KdGl0bGU6ICJELXBsYWNlIEZBUk0gZG9jdW1lbnRhdGlvbjogTW9kdWxlIDIiCmF1dGhvcjogIlR5IFR1ZmYsIEJydW5vIFZpbGVsYSwgYW5kIENhcmxvcyBCb3Rlcm8iCmRhdGU6ICdwcm9qZWN0IGJlZ2FuOiAxNSBNYXkgMjAxNiwgZG9jdW1lbnQgdXBkYXRlZDogYHIgc3RyZnRpbWUoU3lzLnRpbWUoKSwgZm9ybWF0CiAgPSAiJWQgJUIgJVkiKWAnCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKYmlibGlvZ3JhcGh5OiBGQVJNIHBhY2thZ2UuYmliCi0tLQoKCiMgTW9kdWxlIDI6IFNwYWNlIGFuZCBwaHlsb2dlbnkgc3VtbWFyeSBzdGF0aXN0aWNzIAogIFRoaXMgaXMgdGhlIG1hc3RlciBkb2N1bWVudCBmb3IgTW9kdWxlIDIsIGEgZm91bmRhdGlvbmFsIGZ1bmN0aW9uIGluIG91ciBGQVJNIHBhY2thZ2UgdGhhdCBhbmFseXplcyByZXN1bHRzIGZyb20gTW9kdWxlIDEsIHRoZSBvdGhlciBmb3VuZGF0aW9uYWwgZnVuY3Rpb24uIE1vZHVsZSAxIHNpbXVsYXRlcyBhIHNwYXRpYWwgcGF0dGVybiBhbmQgYSBwaHlsb2dlbmV0aWMgdHJlZSBnaXZlbiBhIHNldCBvZiBlbnZpcm9ubWVudGFsIGFuZCBpbmhlcml0YW5jZSBydWxlcyBhbmQgdGhlbiBNb2R1bGUgMiBzdW1tYXJpemVzIHRob3NlIHNpbXVsYXRlZCByZXN1bHRzIHVzaW5nIGEgbGFyZ2Ugc2V0IG9mIHRhcmdldGVkIHN1bW1hcnkgc3RhdGlzdGljcy4gSGVyZSB3ZSBkZXNjcmliZSBvdXIgY2hvaWNlIG9mIHN1bW1hcnkgc3RhdGlzdGljcywganVzdGlmeSB0aG9zZSBjaG9pY2VzIGFzIHBhcnQgb2YgYSBsYXJnZXIgdGhlb3JldGljYWwgY29udGV4dCwgYW5kIHByb3ZpZGUgb3VyIHJlcHJvZHVjYWJsZSBjb2RlIGZvciBleGVjdXRpbmcgdGhlIGFuYXlsc2VzIHlvdXJzZWxmLiBUaGVzZSB0d28gcGFydHMgYXJlIHNlcGVyYXRlZCBpbnRvIG1vZHVsZXMgc28gdGhhdCB0aGV5IGNhbiBhY3QgaW5kZXBlbmRlbnRseS4gQW4gY29tYmluYXRpb24gb2Ygc3BhdGlhbCBwYXR0ZXJuIGFuZCBhc3NvY2lhdGVkIHBoeWxvZ2VueSBtYW55IGJlIHVzZWQgYXMgbG9uZyBhcyB0aGV5IGFyZSBmb3JtYXR0ZWQgY29ycmVjdGx5LiAgICAgICAgIAoKVGhpcyBwaXBlbGluZSB3YXMgZGVzaWduZWQgdG8gYW5hbHl6ZSBhIHNpbXVsYXRlZCB3b3JsZCB3aGVyZSBhbGwgdGhlIGluZm9ybWF0aW9uIGlzIGtub3duIGFib3V0IGJvdGggdGhlIHdvcmxkIGFuZCB0aGUgdHJlZS4gVGhlcmUgaXMgbm8gbWlzc2luZyBpbmZvcm1hdGlvbiwganVzdCBleHRpbmN0IHRyZWVzLiBUaGlzIGlzIG11Y2ggZGlmZmVyZW50IHRoYW4gb3VyIHJlYWwgdHJlZSB0aGF0IGhhcyBsb2FkcyBvZiB1bmNlcnRhaW50eSB1bmV2ZW5seSBkZXN0cmlidXRlZCBhY3Jvc3MgaXQuIFRoZSByZXN1bHQgeW91IHNlZSBkZW1vbnN0cmF0ZWQgcmlnaHQgbm93IGFyZSBvbmUgc2ltdWxhdGVkIHJlc3VsdCBvZiBtYW55LiBJIG5lZWQgdG8gZG8gYSBzaXN0ZXIgcGFnZSB0byB0aGlzIHdlcmUgd2UgZG8gdGhpcyBlbnRpcmUgYW5hbHlzaXMgb24gdGhlIHJlYWwgdHJlZSwgb3IgYmVzdCByZWFsIHRyZWUgd2UndmUgZ290LiAKCldlIGhhdmUgZm91ciB0eXBlcyBvZiBkYXRhIGF2YWlsYWJsZSBmb3IgYXNraW5nIHJlc2VhcmNoIHF1ZXN0aW9ucyB1c2luZyBELXBsYWNlIGRhdGE6IFtwaHlsb2dlbmllc10oI3BoeWxvZ2VuZXRpYy1zdW1tYXJ5LXN0YXRpc3RpY3MpLCBbc3BhdGlhbCBsb2NhdGlvbnNdKCNzcGF0aWFsLWxvY2F0aW9ucyksIHRyYWl0IGlkZW50aXRpZXMsIGFuZCBlbnZpcm9ubWVudGFsIHJlY29uc3RydWN0aW9ucy4gQW55IG9uZSBvZiB0aGVzZSBmb3VyIGRhdGEgdHlwZXMgYWxvbmUgYXJlIHJlbGF0aXZlbHkgaW5mb3JtYXRpb24gcG9vciwgc28gd2UgYXJlIHNlYXJjaGluZyBmb3Igd2F5cyB0byBtb2RlbCBjb25uZWN0aW9ucyBiZXR3ZWVuIHRoZXNlIGRhdGEgdHlwZXMgdG8gZHJhdyBzdHJvbmdlciBjb25jbHVzaW9ucyBvdmVyYWxsLiAKCk90aGVyIG1vZHVsZXMgY2FuIHVzZSB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzIGdlbmVyYXRlZCBmcm9tIHRoaXMgbW9kdWxlIHRvIHRlc3QgaHlwb3RoZXNlcy4gV2UgY3VycmVudGx5IGhhdmUgYSBBQkMgYW5kIFJhbmRvbSBGb3Jlc3QgbW9kdWxlIHN0YXJ0ZWQgYnV0IHRoZXJlIHdpbGwgYmUgbW9yZSB0byBjb21lLiAKClRoZXNlIGFyZSBxdWFudGl0YXRpdmUgY29ubmVjdGlvbnMgdGhhdCB3ZSBhcmUgYXNzdW1lZCBpbiB0aGUgYW5hbHlzZXMsIGJ1dCB3ZSBkb24ndCBhY3R1YWxseSBoYXZlIGFueSBzdXBwb3J0IGluIHRoZSBkYXRhIGZvciBkb2luZyBzby4gCjEuIG5lYXJlc3QgbmVpZ2hib3IgY29ubmVjdGl2aXR5IG1lYXN1cmVzCjIuIEFidW5kYW5jZSBlc3RpbWF0ZXMKMy4gUGFpcndpc2UgaW5mbHVlbmNlIChoaXN0b3J5KSBiZXR3ZWVuIGN1bHR1cmVzLiAKNC4gRW52aXJvbm1lbnRhbCByZWNvbnN0cnVjdGlvbiB2YWxpZGF0aW9uIGV2aWRlbmNlIAoKIyBQaHlsb2dlbmV0aWMgc3VtbWFyeSBzdGF0aXN0aWNzICAKCldob2xlIHRyZWUgdnMuIHBhcnQgb2YgdHJlZT8gVGhlc2Ugc3RhdGlzdGljcyBhcmUgZ2VuZXJhbGx5IHVzZWQgdG8gY29tcGFyZSBvbmUgc2FtcGxlIHRvIGFub3RoZXIuIEZvciBleGFtcGxlLCBhbiBleHBlcmltZW50YWwgY29udHJhc3QgYmV0d2VlbiB0d28gc2l0ZXMsIHR3byBwaHlsb2dlbmV0aWMgZ3JvdXBzLCBvciB0d28gY29tbXVuaXRpZXMgaW4gdHdvIGRpZmZlcmVudCBsb2NhdGlvbnMuIEhlcmUgd2UgYXJlIGNhbGN1bGF0aW5nIHRoZXNlIHN0YXRpc3RpY3MgZm9yIHRoZSBnbG9iYWwgbGFuZ2F1YWdlIHRyZWUgdG8gY29tcGFyZSBhZ2FpbnN0IGdsb2JhbCB0cmVlcyBjcmVhdGVkIGluIG91ciBzaW11bGF0aW9uLiBZb3Ugc3RpbGwgcmV0YWluIHRoZSBhYmlsaXR5IHRvIHN1YnNldCB0aGlzIHRyZWUgb3Igb3RoZXJzIGFuZCBzZW5kIG9ubHkgdGhvc2Ugc3Vic2V0cyB0aHJvdWdoIHRoaXMgY29kZSB0byBjb21wYXJlIHRoZSB2YWx1ZXMgd2l0aCBlYWNoIG90aGVyIGFmdGVyd2FyZHMuIAoKKiBJbnRyb2R1Y3Rpb24gYW5kIGZyYW1ld29yawoqIFtBbHBoYSBEaXZlcnNpdHkgbWV0cmljc10oI2FscGhhLWRpdmVyc2l0eS1tZXRyaWNzKSAKICAxLiBbQnJhbmNoIExlbmd0aCAocmljaG5lc3MgYW5kIGRpdmVyZ2VuY2UpXSgjYnJhbmNoLWxlbmd0aHMpCiAgMi4gW1BhaXJ3aXNlIGRpc3RhbmNlIGJldHdlZW4gdGlwcyAocmljaG5lc3MsIGRpdmVyZ2VuY2UsIGFuZCByZWd1bGFyaXR5KV0oI3BhaXJ3aXNlLWRpc3RhbmNlLWJldHdlZW4tdGlwcykKICAzLiBbUGh5bG9nZW5ldGljIGlzb2xhdGlvbiAoZGl2ZXJnZW5jZSwgYW5kIHJlZ3VsYXJpdHkpXSgjcGh5bG9nZW5ldGljLWlzb2xhdGlvbikKICA0LiBbTmVhcmVzdCBOZWlnaGJvciAoZGl2ZXJnZW5jZSwgYW5kIHJlZ3VsYXJpdHkpXSgjbmVhcmVzdC1waHlsb2dlbmV0aWMtbmVpZ2hib3IpIAoqIFtCZXRhIERpdmVyc2l0eV0oI2JldGEtZGl2ZXJzaXR5KQoqIFtUcmVlIHRvcG9sb2d5XSgjdHJlZS10b3BvbG9neSkKKiBbTWFjcm9ldm9sdXRpb25hcnkgcmF0ZXNdKCNtYWNyb2V2b2x1dGlvbmFyeS1yYXRlcykKCgpBbGwgdHJlZXMgYXJlIHVsdHJhbWV0cmljLgoKCgojIyBJbnRyb2R1Y3Rpb24gYW5kIGZyYW1ld29yawoKCiAgVGhlIGNob2ljZSBvZiBwaHlsb2dlbmV0aWMgYW5hbHlzZXMgYW5kIG9yZ2FuaXphdGlvbmFsIHNjaGVtZSBpcyBiYXNlZCBvbiB0aGUgc3VnZ2VzdGlvbnMgb2YgQFR1Y2tlcjIwMTYuIEhlcmUgYXJlIGEgZmV3IGltYWdlcyBmcm9tIHRoYXQgcGFwZXIgZm9yIGFuIG92ZXJ2aWV3OiAgCgoKIVtGcm9tIEBUdWNrZXIyMDE2XShJbWFnZXMvVHVja2VyXzIwMTYvdHJlZV9jb25jZXB0LmpwZykKIVtGcm9tIEBUdWNrZXIyMDE2XShJbWFnZXMvVHVja2VyXzIwMTYvYWxwaGFfUENBLmpwZykKCiFbRnJvbSBAVHVja2VyMjAxNl0oSW1hZ2VzL1R1Y2tlcl8yMDE2L1RocmVlX3R5cGVfc3VtbWFyeS5qcGcpCgoKIVtGcm9tIEBUdWNrZXIyMDE2XShJbWFnZXMvVHVja2VyXzIwMTYvdHV0b3JpYWwuanBnKQoKYGBge3J9CmxpYnJhcnkoa25pdHIpCmxpYnJhcnkocGh5dG9vbHMpCmxpYnJhcnkoRkFSTSkKbGlicmFyeShST0NSKQpsaWJyYXJ5KHNwZGVwKQpgYGAKCgoKYGBge3J9CmxvYWQoJ34vRG93bmxvYWRzL2Rvd25sb2FkLlJkYXRhJykKCnRoaXNfdHJlZSA8LSBteU91dCRteXRyZWUKdGhpc193b3JsZCA8LSBteU91dCRteVdvcmxkCmBgYAoKYGBge3J9CnN0cih0aGlzX3dvcmxkKQpzdHIodGhpc190cmVlKQpgYGAKCgojI0FscGhhIGRpdmVyc2l0eSBtZXRyaWNzCgojIyMgQnJhbmNoIExlbmd0aHMKICBCcmFuY2ggbGVuZ3RoIGRhdGEgaXMgZW1iZWRkZWQgaW4gdGhlIHRyZWUgb2JqZWN0IHByb3ZpZGVkIHRvIHRoaXMgZnVuY3Rpb24uIFRoZSBmaXJzdCBzdGVwIGluIHN1bW1hcml6aW5nIHRoZSBsZW5ndGhzIGlzIHRvIGV4dHJhY3QgdGhvc2UgZGF0YSBmcm9tIHRoZSB0cmVlIG9iamVjdC4gVGhlc2UgZGF0YSBhcmUgY2FsbGVkICdlZGdlcycgaW4gdGhlIHRyZWUgb2JqZWN0LiBXZSBleHRyYWN0IGJyYW5jaCBsZW5ndGhzIGFuZCBjcmVhdGUgYW4gb2JqZWN0IGNhbGxlZCAnQnJhbmNoX2xlbmd0aHMnIGZvciBwYXNzaW5nIG9uIHRvIHRoZSBvdGhlciBzdW1tYXJ5IGZ1bmN0aW9ucy4gVGhlIGhpc3RvZ3JhbSBiZWxvdyBzaG93cyB0aGUgZnJlcXVlbmN5IG9mIGRpZmZlcmVudCBicmFuY2ggbGVuZ3RocyBmb3VuZCB0aHJvdWdob3V0IHRoZSB0cmVlLiAKICAKYGBge3J9CkJyYW5jaF9MZW5ndGhzIDwtIHRoaXNfdHJlZSRlZGdlLmxlbmd0aApgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQogIyBwbG90IHRoZSBicmFuY2ggbGVuZ3RocwpoaXN0KEJyYW5jaF9MZW5ndGhzLCB4bGFiPSJCcmFuY2ggTGVuZ3RocyIsIG1haW49IiIsIGJyZWFrcz0xMDAwLCBib3JkZXI9TkEsIAogICAgIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0wLjkpKQpgYGAKV2UgY2FuIHN1bW1hcml6ZSBicmFuY2ggbGVuZ3RocyBhY2NvcmRpbmcgdG8gbm9ybWFsIHN1bW1hcnkgc3RhdGlzdGljcywgYnV0IGl0IGNhbiBiZSBkaWZmaWN1bHQgdG8gYXNzaWduIGV2b2x1dGlvbmFyeSBtZWFuaW5nIHRvIHNvbWUgb2YgdGhlc2UgbWV0cmljcyBhbmQgc28gdGhleSBhcmUgbm90IHJlZ3VsYXJseSB1c2VkIGFzIGJlc3QgSSBjYW4gdGVsbC4gVGhpcyBsYWNrIG9mIG1lYW5pbmcgZG9lcyBub3QgbWVhbiB0aGF0IHRoZXNlIHN0YXRpc3RpY3MgY291bGRuJ3QgYmUgdXNlZCB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIGxhcmdlIHNpbXVsYXRlZCB0cmVlcy4gCmBgYHtyfQptZWFuX2JyYW5jaF9sZW5ndGggPC0gbWVhbihCcmFuY2hfTGVuZ3RocykKdmFyaWFuY2VfYnJhbmNoX2xlbmd0aCA8LSB2YXIoQnJhbmNoX0xlbmd0aHMpClNEX2JyYW5jaF9sZW5ndGggPC0gc2QoQnJhbmNoX0xlbmd0aHMpCmBgYAoKCmBgYHtyLCBlY2hvPUZBTFNFfQpwYXN0ZSgibWVhbiBicmFuY2ggbGVuZ3RoID0gIiwgbWVhbl9icmFuY2hfbGVuZ3RoKQpwYXN0ZSgidmFyaWFuY2UgaW4gYnJhbmNoIGxlbmd0aHMgPSAiLCB2YXJpYW5jZV9icmFuY2hfbGVuZ3RoKQpwYXN0ZSgic3RhbmRhcmQgZGV2aWF0aW9uIGluIGJyYW5jaCBsZW5ndGhzID0gIiwgU0RfYnJhbmNoX2xlbmd0aCkKCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CnBhcihtYXI9YygyLDQsMCwwKSkKYm94cGxvdChCcmFuY2hfTGVuZ3RocywgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPTAuNSksIAogICAgICAgIGJvcmRlcj1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0xKSwgeWxhYj0iQnJhbmNoIExlbmd0aHMiKQpgYGAKCiMjIyMgUGh5bG9nZW5ldGljIGRpdmVyc2l0eSAoJFBEJCkKUGh5bG9nZW5ldGljIGRpdmVyc2l0eSAoJFBEJCkgaXMgdGhlIHN1bW1hdGlvbiAoJFxzdW0kKSBvZiBhbGwgYnJhbmNoIGxlbmd0aHMgY29ubmVjdGluZyBzcGVjaWVzIHRvZ2V0aGVyLCB3aGVyZSAkQl97dH0kIGlzIHRoZSBzZXQgb2YgaW5jbHVkZWQgdGlwcyBhbmQgJExfe2J9JCBpcyBCcmFuY2ggbGVuZ3RocyBbQEZhaXRoMTk5Ml0uIFRoaXMgaXMgYW4gYW5jaG9yIHRlc3QsIHdoaWNoIG1lYW5zIGl0IGlzIHJlZ3VsYXJseSB1c2VkLCB3ZWxsIHVuZGVyc3Rvb2QsIGFuZCB3ZSBzaG91bGQgdXNlIGl0IHRvIGFuY2hvciBvdXIgd29yayB0byBwYXN0IHdvcmsuIFBEIGlzIGEgcmljaG5lc3MgbWVhc3VyZSwgaXQgdGVsbHMgdXMgaG93IG11Y2ggZXZvbHV0aW9uYXJ5IGhpc3RvcnkgaXMgYXNzb2NpYXRlZCB3aXRoIGEgc2V0IG9mIHRpcHMuICAKCiQkUEQgPSBcc3VtX3tiIFxpbiBCX3t0fX1ee31MX3tifSQkCiAKYGBge3J9CiMgQW5jaG9yIHRlc3QgPSBQRCAoRmFpdGgncyBwaHlsb2dlbmV0aWMgZGl2ZXJzaXR5KQpQeWxvX2RpdmVyc2l0eV9pc19zdW1fb2ZfQkwgPC0gc3VtKEJyYW5jaF9MZW5ndGhzKQpQeWxvX2RpdmVyc2l0eV9pc19zdW1fb2ZfQkwKYGBgCgoKIFRoZXJlIGFyZSB2YXJpYXRpb25zIG9uIHRoaXMgbWVhc3VyZSB0aGF0IHdlIGhhdmUgTk9UIGltcGxlbWVudGVkIGhlcmUuIEl0IGlzIHBvcHVsYXIgdG8gc2NhbGUgdGhpcyBtZWFzdXJlIGFjY29yZGluZyB0byBzb21lIGVjb2xvZ2ljYWwgZHJpdmVyLiBAQmFya2VyMjAwMiBzY2FsZXMgYnJhbmNoIGxlbmd0aHMgKCRMX3tifSQpIGJ5IG11bHRpcGx5aW5nIHRoZW0gYWdhaW5zdCB0aGUgYWJ1bmRhbmNlIG9mIGluZGl2aWR1YWxzIGF0IGF0IHRpcCAoJEFfe2J9JCkuIE90aGVycyBbQFJvc2F1ZXIyMDA5XSwgc2NhbGUgdGhlbSBieSB0aGVpciByYW5nZSBzaXplIGluc3RlYWQgKCRSX3tifSQpLiAKIAogJCRcRGVsdGEgbiBQRCA9IFxzdW1fe2IgXGluIEJfe3R9fV57fUFfe2J9TF97Yn0kJAokJFBFID0gXHN1bV97YiBcaW4gQl97dH19Xnt9XGRmcmFje0xfe2J9fXtSX3tifX0kJApBcmd1ZWluZyB0aGF0IHByb3BvcnRpb25hbCBhYnVuZGFuY2UgcGh5bG9nZW5ldGljIGRpdmVyc2l0eSAoJFBEX3tBYn0kKSBpcyBtb3JlIGVmZmVjdGl2ZSB0aGFuIHRoZSBzdGFuZGFyZCBQRCBjYWxjdWxhdGVkIGZyb20gcmF3IGFidW5kYW5jZSwgQFZlbGxlbmQyMDExIHBlbm5lZCBhIG5ldyB2ZXJzaW9uIG9mIFBEIHdoZXJlICRCJCBpcyB0aGUgdG90YWwgbnVtYmVyIG9mIGJyYW5jaCBsZW5ndGhzICgkTF97Yn0kKS4gTm90ZTogV2UgZG9uJ3QgaGF2ZSBhYnVuZGFuY2UgZGF0YSByaWdodCBub3cgZm9yIHRoZSBodW1hbiBwcm9qZWN0IHNvIHRoaXMgbWV0cmljIGlzIG5vdCBjdXJyZW50bHkgdmVyeSBoZWxwZnVsLiAgIAokJFBEX3tBYn0gPSBCICogXGRmcmFje1xzdW1fe2IgXGluIEJfe3R9fV57fUFfe2J9TF97Yn19e1xzdW1fe2IgXGluIEJfe3R9fV57fUFfe2J9fSQkCgpgYGB7cn0KI0NhbGN1bGF0ZSBCCm51bWJlcl9vZl9icmFuY2hlcyA8LSBsZW5ndGgoQnJhbmNoX0xlbmd0aHMpCm51bWJlcl9vZl9icmFuY2hlcwpgYGAKCiMjIyMgQXZlcmFnZSBwaHlsb2dlbmV0aWMgZGl2ZXJzaXR5ICgkYXZQRCQpCkF2ZXJhZ2UgcGh5bG9nZW5ldGljIGRpdmVyc2l0eSAoJGF2UEQkKSBbQENsYXJrZTIwMDFdIGlzIGEgYnJhbmNoIGxlbmd0aC1iYXNlZCBkaXZlcmdlbmNlIGluZGljZXMgd2hlcmUgUEQgaXMgZGl2aWRlZCBieSB0aGUgdG90YWwgbnVtYmVyIG9mIHRpcHMgKCRTJCkgaW4gdGhlIHRyZWUuIAokJGF2UEQgPSBcZGZyYWN7UER9e1N9JCQKYGBge3J9Ck51bWJlcl9vZl90aXBzIDwtIGxlbmd0aCh0aGlzX3RyZWUkdGlwLmxhYmVsKQphdmVyYWdlX3BoeWxvZ2VuZXRpY19kaXZlcnNpdHkgPC0gUHlsb19kaXZlcnNpdHlfaXNfc3VtX29mX0JMIC8gTnVtYmVyX29mX3RpcHMKYXZlcmFnZV9waHlsb2dlbmV0aWNfZGl2ZXJzaXR5CmBgYAoKClRoZXJlIGlzIGFsc28gYSBwcm9wb3J0aW9uYWwgYWJ1bmRhbmNlIHZlcnNpb24gb2YgYXZlcmFnZSBwaHlsb2dlbmV0aWMgZGl2ZXJzaXR5ICgkYXZQRF97QWJ9JCkgW0BUdWNrZXIyMDE2XS4gQWdhaW4sIHdlIGRvbid0IGhhdmUgYWJ1bmRhbmNlIHZhbHVlcyB5ZXQgZm9yIEQtcGxhY2UuIAokJGF2UERfe0FifSA9IFxkZnJhY3tCICogXGRmcmFje1xzdW1fe2IgXGluIEJfe3R9fV57fUFfe2J9TF97Yn19e1xzdW1fe2IgXGluIEJfe3R9fV57fUFfe2J9fX17U30kJAoKCiMjIyBQYWlyd2lzZSBkaXN0YW5jZSBiZXR3ZWVuIHRpcHMKClRoaXMgaXMgdGhlIHBhdHJpc3RpYyBkaXN0YW5jZSwgdGhlIHN1bSBvZiB0aGUgYnJhbmNoIGxlbmd0aHMgZm9sbG93aW5nIHRoZSBzaG9ydGVzdCBkaXN0YW5jZSBiZXR3ZWVuIHR3byB0aXBzIGluIGEgdHJlZSwgaW1wbGVtZW50ZWQgYXMgYSBkaXN0YW5jZSBtYXRyaXggd2hlcmUgZXZlcnkgdGlwIGlzIGNvbXBhcmVkIHRvIGV2ZXJ5IG90aGVyIHRpcC4gVGhpcyBkaXN0YW5jZSBmdW5jdGlvbiBjYW4gYmUgYW55dGhpbmcuIFdlIHVzZSBldWNsaWRlYW4gYW5kIGVudmlyb25tZW50YWwgZGlzdGFuY2UgbWF0cmljZXMgaGVhdmlseSBpbiB0aGUgc3BhdGlhbCBhbmFseXNlcy4gCgojIyMjIENhbGN1bGF0ZSB0aGUgcGF0cmlzdGljIGRpc3RhbmNlIGJldHdlZW4gdHdvIHRheGEsIGZvciBhbGwgdGF4YQpDYWxjdWxhdGUgdGhlIHBhdHJpc3RpYyBkaXN0YW5jZSBiZXR3ZWVuIHR3byB0YXhhIHVzaW5nIHRoZSBSIHBhY2thZ2UgJ3BoeXRvb2xzJywgdGhpcyBmdW5jdGlvbiB0YWtlcyBhICdwaHlsbycgdHJlZSBvYmplY3QgYW5kIHJldHVybnMgYSBkaXN0YW5jZSBtYXRyaXggYmV0d2VlbiB0aXBzLiBOZWVkIG9yaWdpbmFsIGNpdGF0aW9uLgoKYGBge3J9CiMjIFBhaXJ3aXNlIGRpc3RhbmNlIGJldHdlZW4gdGlwcyAtIEZyb20gbGlicmFyeShhcGUpIGluIGxpYnJhcnkocGh5dG9vbHMpClBhaXJ3aXNlX2Rpc3QgPC0gY29waGVuZXRpYyh0aGlzX3RyZWUpCmBgYAp5aWVsZHMgYSBkaXN0YW5jZSBtYXRyaXggKGxpc3Qgb2YgMkQgbWF0cmljZXMpIG9mIGFsbCBkaXN0YW5jZXMgYmV0d2VlbiB0YXhhLgoKCmBgYHtyLCBlY2hvPUZBTFNFfQpzdHIoUGFpcndpc2VfZGlzdCkKYGBgCgojIyMjIFN1bSBvZiBhbGwgcGFpcndpc2UgZGlzdGFuY2VzICgkRiQpCk5vdyB3ZSBjYW4gdXNlIGEgc2V0IG9mIHN1bW1hcnkgc3RhdGlzdGljcyB0byBkZXNjcmliZSB0aG9zZSBwYWlyd2lzZSBkaXN0YW5jZXMuIFRoZSBzdW0gb2YgYWxsIHBhaXJ3aXNlIGRpc3RhbmNlcywgJEYkLCBpcyBmb3JtYWxseSBjYWxsZWQgJ0V4dGVuc2l2ZSBxdWFkcmF0aWMgZW50cm9weScuIFtASXpzYWsyMDAwXS4gSnVzdCBhcyBpdCB3YXMgd2l0aCBicmFuY2ggbGVuZ3RocywgdGhpcyBpcyBhIHJpY2huZXNzIG1lYXN1cmUgYW5kLCBhY2NvcmRpbmdseSwgc2hvdWxkIGJlIHVzZWQgdG8gYW5zd2VyIHJpY2huZXNzIHF1ZXN0aW9ucy4gCgokJEYgPSBcc3VtX3tpfSBcc3VtX3tqfSBkX3tpan0kJApgYGB7cn0KIyBGIC0tIEV4dGVuc2l2ZSBxdWFkcmF0aWMgZW50cm9weQpGX3F1YWRyYXRpY19lbnRyb3B5X2lzX3N1bV9vZl9QRCA8LSBzdW0oUGFpcndpc2VfZGlzdCkKRl9xdWFkcmF0aWNfZW50cm9weV9pc19zdW1fb2ZfUEQKYGBgCgojIyMjIE1lYW4gcGFpcndpc2UgZGlzdGFuY2UgKE1QRCkKTWVhbiBpbnRlci1zcGVjaWVzIGRpc3RhbmNlcy4gVGhlIG1lYW4gb2YgYWxsIHBhaXJ3aXNlIGRpc3RhbmNlcywgJE1QRCQgKGEuay5hLiAkQXZURCQsIGFuZCAkXERlbHRhXnsrfSQpLCBpcyB0aGUgbWVhbiBkaXN0YW5jZSBiZXR3ZWVuIHNwZWNpZXMuIFtAQ2xhcmtlMTk5ODsgQFdlYmIyMDAyOyBAV2ViYjIwMDg7IEBLZW1iZWwyMDEwXS4KJCRNUEQgPSBcZGZyYWN7XHN1bV97aWp9IGRfe2lqfX17UyhTLTEpfSQkCgpgYGB7cn0KIyBBbmNob3IgdGVzdCA9IE1QRCAobWVhbiBwYWlyd2lzZSBkaXN0YW5jZSkKTWVhbl9wYWlyd2lzZV9kaXN0YW5jZSA8LSAKICBQYWlyd2lzZV9kaXN0IC8gKE51bWJlcl9vZl90aXBzICogKE51bWJlcl9vZl90aXBzIC0gMSkgKSAKYGBgCgpgYGB7ciwgZWNobz1GQUxTRX0Kc3RyKE1lYW5fcGFpcndpc2VfZGlzdGFuY2UpCmBgYAoKIyMjIyBNUEQgYW5jaG9yZWQgdG8gdGhlIHJvb3QgClRoZXJlIGlzIGFuIGV4dGVudGlvbiB0byBtZWFuIHBhaXJ3aXNlIGRpc3RhbmNlIGNhbGN1bGF0aW9ucyBmcm9tIEBIZWxtdXMyMDEwIGNhbGxlZCAkUFNWJCwgJFBTUiQsIGFuZCAkUFNFJCwgcGh5bG9nZW5ldGljIHNwZWNpZXMgdmFyaWFiaWxpdHksIHBoeWxvZ2VuZXRpYyBzcGVjaWVzIHJpY2huZXNzLCBhbmQgcGh5bG9nZW5ldGljIHNwZWNpZXMgZXZlbm5lc3MuIFRoZXNlIG1lYXN1cmVzIHRha2UgdGhlIGJhc2ljIHBhaXJ3aXNlIGRpc3RhbmNlIGNhbGN1bGF0aW9ucyBhbmQgYW5jaG9yIHRoZW0gdG8gdGhlIHJvb3Qgb2YgdGhlIHRyZWUgc28gZGlzdGFuY2VzIGhhdmUgYSBjb21tb24gZGVub21pbmF0b3IuIFRoaXMgZXh0ZW50aW9uIGlzIGltcGxlbWVudGVkIGJ5IHVzaW5nIHRoZSBzYW1lIGVxdWF0aW9ucywganVzdCB3aXRoIGEgY29uc3RyYWluZWQgc2V0IG9mICRkX3tpan0kIGNvbmRpdGlvbnMuIFNwZWNpZmljYWxseSwKCgoKCiQkUFNWID0gTVBEID0gXGRmcmFje1xzdW1fe2lqfSBkX3tpan19e1MoUy0xKX0kJAokJFBTUiA9IFxzdW1fe2l9IHsoXGRmcmFjezF9e1MtMX0gXHN1bV97an0ge2Rfe2lqfX0pfSQkCiQkUFNFID0gXGRmcmFje1N9e1MtMX0gXHN1bV97aWp9IGRfe2lqfXBfe2l9cF97an0kJAoKCndpdGggdGhlc2Ugc3BlY2lmaWMgdmFsdWVzIG9mICRkX3tpan0kCgokJApkX3tqaX09MC41KihjX3tpaX0gKyBjX3tqan0gLSBjX3tpan0pIFxcIApcIFxcCm9yIFxcClwgXFwKZF97aWp9ID0gMSAtIGNfe2lqfSAvIChcc3FydHtjX3tpaX1jX3tqan19KSAKJCQKYW5kCiQkCmNfe2lpfSA9IHRoZSBcIHN1bSBcIG9mIFwgYnJhbmNoIFwgbGVuZ3RocyBcIGZyb20gXCB0aXAgXCBpICBcIHRvIFwgdGhlIFwgcm9vdCBcIG9mIFwgdGhlIFwgcGh5bG9nZW5ldGljIFwgdHJlZS4gXFwKXCBcXApjX3tpan0gPSB0aGUgXCBzdW0gXCAgb2YgXCBicmFuY2ggXCBsZW5ndGhzIFwgZnJvbSBcIGZpcnN0IFwgY29tbW9uIFwgYW5jZXN0b3IgXCBmb3IgXCBpIFwgYW5kIFwgaiBcIHRvIFwgdGhlIFwgcm9vdC4KJCQKCgoKIyMjIyBBdmVyYWdlIGRpc3RhbmNlIGJldHdlZW4gdHdvIHJhbmRvbWx5IGNob3NlbiBzcGVjaWVzCiRKJCwgSW50ZW5zaXZlIHF1YWRyYXRpYyBlbnRyb3B5LCB3aGljaCBpcyB0aGUgYXZlcmFnZSBkaXN0YW5jZSBiZXR3ZWVuIHR3byByYW5kb21seSBjaG9zZW4gc3BlY2llcyBbQEl6c2FrMjAwMF0KJCRKID0gXGRmcmFje1xzdW1fe2lqfWRfe2lqfX17U14yfSAkJAoKCgoKIyMjIyBTaW1wc29uJ3MgZGl2ZXJzaXR5IGluZGV4IGZvciBwYWlyd2lzZSBkaXN0YW5jZQpUaGVyZSBoYXMgYmVlbiBhIGxvbmcgZWZmb3J0IHRvIHBlbiBhIHBoeWxvZ2VuZXRpYyBhbmFsb2d5IHRvIGEgU2ltcHNvbidzIGRpdmVyc2l0eSBpbmRleC4gW0BSYW8xOTgyOyBAQ2xhcmtlMTk5ODsgQFBhdm9pbmUyMDA1OyBASGFyZHkyMDA3OyBAV2ViYjIwMDI7IEBXZWJiMjAwODsgQEtlbWJlbDIwMTBdLiBUaGUgY29uY2x1c2lvbiBzZWVtcyB0byBiZSB0aGF0IHRoaXMgbWVhc3VyZSBpcyBlcXVpdmlsZW50IHRvIHNjYWxpbmcgJE1QRCQgYnkgYWJ1bmRhbmNlICRwX3tpfSQgYW5kICRwX3tqfSQgdG8gZ2V0ICRNUERfe0FifSQuIFRoaXMgaXMgYWxzbyBhIHNwZWNpYWwgY2FzZSBvZiBSYW8ncyBRdWFkcmF0aWMgRW50cm9weSwgJFJvZSdzIFFFJC4gTm90ZTogbm90IHVzaW5nIGFidW5kYW5jZSBtZWFzdXJlcyB5ZXQgZm9yIEQtcGxhY2UgZGF0YS4gCgokJE1QRF97QWJ9ID0gXHN1bV97aX0gXHN1bV97an0gZF97aWp9IHBfe2l9IHBfe2p9JCQKCgoKCiMjIyMgSW50ZXJzcGVjaWZpYyBjb21wYXJpc29ucyBvZiBwYWlyd2lzZSBkaXN0YW5jZXMKVGhlIGludGVyc3BlY2lmaWMgdmFyaWFudCAocmF0aGVyIHRoYW4gdGhlIGludHJhc3BlY2lmaWMgZGVmYXVsdCBkZXNjcmliZWQgYWJvdmUpIGRlZmluZXMgdGhlIGV4cGVjdGVkIHBoeWxvZ2VuZXRpYyBkaXN0YW5jZSBiZXR3ZWVuIHR3byBpbmRpdmRpdWFscyByYW5kb21lbHkgZHJhd24gY29uZGl0aW9uYWxseSBvbiB0aGUgZmFjdCB0aGF0IHRoZXkgaW5kaXZkdWxhcyBmcm9tIGRpZmZlcmVudCBzcGVjaWVzLiAKJCRJbnRlck1QRF97QWJ9ID0gXGRmcmFje1xzdW1fe2l9IFxzdW1fe2ogXG5lIGl9IGRfe2lqfSBwX3tpfSBwX3tqfSB9e1xzdW1fe2l9IFxzdW1fe2ogXG5lIGl9IGRfe2lqfSBwX3tpfSBwX3tqfX0gICQkCgoKCiMjIyMgVmFyaWFuY2UgaW4gcGFpcndpc2UgZGlzdGFuY2VzICgkVlBEJCkKVmFyaWFuY2UgaW4gcGFpcndpc2UgZGlzdGFuY2VzLCAkVlBEJCAoYS5rLmEuICRWYXJURCQgYW5kICRcTGFtYmRhXiskKSwgaXMgYSByZWd1bGFyaXR5IGluZGljZXMuIEBDbGFya2UyMDAxIFZhcmlhbmNlIGlzIHJlbGF0aXZlIHRvIHRpcHMsICRTJCwgbm90IHRvIHRvdGFsIGJyYW5jaGVzICgkQiQgZnJvbSBhYm92ZSkuIFRoZXNlIGFyZSB0aGUgcmVzaWR1YWxzLCB0aGV5IGNvbXBhcmUgZWFjaCBpbmRpdmlkdWFsIHBhaXJ3aXNlIGNvbm5lY3Rpb24gdG8gdGhlIG92ZXJhbGwgbWVhbi4gCgokJFZQRCA9IFxkZnJhY3sxfXtTKFMtMSl9IChcc3VtX3tpfSBcc3VtX3tqIFxuZSBpfSB7KGRfe2lqfSAtIE1QRCleMn0pJCQKCgoKCmBgYHtyfQojbmVlZCB0byBhZGp1c3QgdG8gZXF1YXRpb24gYWJvdmUhCgojUGFpcndpc2UgZGlzdGFuY2UvYWxsIGRpc3RhbmNlcyAtLSBWYXJpYW5jZSBvZiBwYWlyd2lzZSBkaXN0YW5jZXMKCiMgQW5jaG9yIHRlc3QgPSBWUEQgKHZhcmlhdGlvbiBvZiBwYWlyd2lzZSBkaXN0YW5jZSkgIAoKdmFyaWFuY2VfcGFpcndpc2VfZGlzdGFuY2UgPC0gdmFyKGFzLnZlY3RvcihQYWlyd2lzZV9kaXN0KSkKYGBgCgoKVmFyaWFudHMgb2YgJFZQRCQgYXJlICRWUERfe2FifSQgYW5kICRJbnRlclBWRF97QWJ9JCwgd2hlcmUgdmFyaWFuY2UgaXMgc2NhbGVkIGJ5IGFidW5kYW5jZSBvciBjb21wYXJlZCBpbiBhbmQgb3V0IG9mIHNwZWNpZXMuIFRoZXNlIGFyZSBhbHNvIHJlZ3VsYXJpdHkgaW5kaWNlcy4gCgokJApWUERfe0FifT0gCihcc3VtX3tpfSBcc3VtX3tqfSBuX3tpfSBuX3tqfSkgKgpcZGZyYWN7XHN1bV97aX0gXHN1bV97an0gbl97aX0gbl97an0gKGRfe2lqfSAtIE1QRF97QWJ9KV4yfQp7KFxzdW1fe2l9IFxzdW1fe2p9IG5fe2l9IG5fe2p9KV4yIC0gXHN1bV97aX0gXHN1bV97an0gKG5fe2l9IG5fe2p9KV4yfQpcXApvcgpcXApJbnRlclZQRF97QWJ9ID0gCihcc3VtX3tpfSBcc3VtX3tqIFxuZSBpfSBuX3tpfSBuX3tqfSkgKgpcZGZyYWN7XHN1bV97aX0gXHN1bV97aiBcbmUgaX0gbl97aX0gbl97an0gKGRfe2lqfSAtIEludGVyTVBEX3tBYn0pXjJ9CnsoXHN1bV97aX0gXHN1bV97aiBcbmUgaX0gbl97aX0gbl97an0pXjIgLSBcc3VtX3tpfSBcc3VtX3tqIFxuZSBpfSAobl97aX0gbl97an0pXjJ9CiQkCgojIyMgTmVhcmVzdCBwaHlsb2dlbmV0aWMgbmVpZ2hib3IKCiMjIyMgRGl2ZXJnZW5jZSBpbmRpY2VzCkRpdmVyZ2VuY2UgaW5kaWNlcyB1c2luZyBuZWFyZXN0IGRpc3RhbmNlOiAkTU5URCQgYW5kICRNTlREX3tBYn0kLCBNZWFuIG5lYXJlc3QgdGF4b24gZGlzdGFuY2UgYW5kIEFidW5kYW5jZS13ZWlnaHRlZCBNTlREIFtAV2ViYjIwMDI7IEBXZWJiMjAwODsgQEtlbWJlbDIwMTBdLiAKCiRNTlREJCwgbWVhbiBuZWFyZXN0IHRheG9uIGRpc3RhbmNlLCBpcyB0aGUgbWVhbiBzaG9ydGVzdCBkaXN0YW5jZSBmcm9tIGEgc3BlY2llcyB0byBhbGwgb3RoZXIgaW4gdGhlIGFzc2VtYmxhZ2UgW0BXZWJiMjAwMjsgQFdlYmIyMDA4OyBAS2VtYmVsMjAxMF0uICAKJCQKTU5URCA9IApcZGZyYWN7MX17U30KXHN1bV97aX0KZF97aV97bWlufX0KJCQKCiRNTlREX3tBQn0kLCBhYnVuZGFuY2UgYWRqdXN0ZWQgbWVhbiBuZWFyZXN0IHRheG9uIGRpc3RhbmNlLiBBZGp1c3RlZCBieSBzcGVjaWVzIHByb3BvcnRpb25zIChpLmUuIHNwZWNpZXMnIHJlbGF0aXZlIGFidW5kYW5jZXMpIFtAV2ViYjIwMDI7IEBXZWJiMjAwODsgQEtlbWJlbDIwMTBdICAgCiQkCk1OVERfe0FifSA9IApcc3VtX3tpPTF9XntTfQpbZF97aV97bWlufX0gKiBwX3tpfV0KJCQKCiMjIyMgUmVndWxhcml0eSBpbmRpY2VzClJlZ3VsYXJpdHkgaW5kaWNlcyB1c2luZyBuZWFyZXN0IGRpc3RhbmNlczogJFZOVEQkLCAkVk5URF97QWJ9JCwgJFBFX3tldn0kLiAgCgokVk5URCQsIFZhcmlhbmNlIGluIG5lYXJlc3QgdGF4b24gZGlzdGFuY2VzLCBpcyB0aGUgdmFyaWFuY2UgaW4gbmVhcmVzdCBwYWlyd2lzZSBkaXN0YW5jZSBbQFR1Y2tlcjIwMTZdLgokJApWTlREID0gXGRmcmFjezF9e1N9ClxzdW1fe2ktMX1ee1N9ClsoZF97aV97bWlufX0gLSBNTlREKV4yXQokJAokVk5URF97QWJ9JCwgQWJ1bmRhbmNlIHdlaWdodGVkIHZhcmlhbmNlIGluIG5lYXJlc3QgdGF4b24gZGlzdGFuY2VzLCBpcyBzY2FsZXMgYnkgYWJ1bmRhbmNlIGluIHRoZSBzYW1lIHdheSBhcyBkZXNjcmllZCBhYm92ZSBbQFR1Y2tlcjIwMTZdLgokJApWTlREX3tBYn0gPSBcZGZyYWMKeyhcc3VtX3tpfSBuX3tpfSkgXHN1bV97aX0gbl97aX0gKGRfe2lfe21pbn19IC0gTU5URF97QWJ9KV4yfQp7KFxzdW1fe2l9IG5fe2l9KV4yIC0gXHN1bV97aX0gbl97aX0gXjJ9CiQkCgojIyMjIFBoeWxvZ2VuZXRpYyB2ZXJzaW9uIG9mIHRoZSBmdW50aW9uYWwgJEZFX3t2ZX0kIGluZGV4CiRQRV97dmV9JCwgcGh5bG9nZW5ldGljIGV2ZW5uZXNzIGlzIGEgcGh5bG9nZW5ldGljIHZlcnNpb24gb2YgdGhlIGZ1bnRpb25hbCAkRkVfe3ZlfSQgaW5kZXguIEZpcnN0IGEgbWluaW11bSBzcGFubmluZyB0cmVlICgkTVNUJCkgaXMgY29tcHV0ZWQgdXNpbmcgdGhlIGNvcGhlbmV0aWMgZGlzdGFuY2Ugb2J0YWluZWQgZnJvbSB0aGUgcGh5bG9nZW5ldGljIHRyZWUuIFRoZSAkTVNUJCBjb250YWlucyAkUy0xJCBCcmFuY2hlcyBjb25uZWN0aW9uIHRoZSAkUyQgc3BlY2llcy4gV2UgZGVub3RlICRsJCBhIGJyYW5jaCBvbiB0aGUgJE1TVCQsICRkaXN0KGksaikkIGlzIHRoZSBsZW5ndGggdGhlIGJyYW5jaCAkbCQgdGhhdCBjb25uZWN0cyBzcGVjaWVzICRpJCBhbmQgJGokLiAkbl97aX0kIGlzLCBhcyBkZWZpbmVkIGFib3ZlLCB0aGUgYWJ1bmRhbmNlIG9mIHNwZWNpZXMgJGkkIGluIHRoZSBhc3NlYmxhZ2UgW0BWaWxsZWdlcjIwMDg7IEBEZWhsaW5nMjAxNF0uIAoKJCQKV2VpZ2h0ZWQgXCBldmVubmVzczogXFwKRVdfe2l9ID0gXGRmcmFje2Rpc3QoaSxqKX0KeyhuX3tpfSArIG5fe2p9KS8oXHN1bV97az0xfV57U31uX3trfSl9IFxcClwgXFwKUGFydGlhbCBcIHdlaWdodGVkIFwgZXZlbm5lc3M6IFxcIApQRVdfe2x9ID0gXGRmcmFjCntFV197bH19Cntcc3VtX3tsPTF9XntTLTF9IEVXX3tsfX0gXFwKXCBcXApQaHlsb2dlbmV0aWMgXCBldmVubmVzczogXFwKUEVfe3ZlfSA9IFxkZnJhYwp7XHN1bV97bD0xfV57Uy0xfSBtaW4oUEVXX3tsfSwgXGRmcmFjezF9e1MtMX0pIC0gKFxkZnJhY3sxfXtTLTF9KX0KezEtIChcZGZyYWN7MX17Uy0xfSl9CiQkCgojIyMgUGh5bG9nZW5ldGljIGlzb2xhdGlvbgpBIHBoeWxvZ2VuZXRpYyBpc29sYXRpb24gaW5kZXggcmVwcmVzZW50cyB0aGUgcmVsYXRpdmUgaXNvbGF0aW9uIG9mIGEgZ2l2ZW4gc3BlY2llcyB3aXRoaW4gYSBwaHlsb2dlbmV0aWMgdHJlZS4gU2V2ZXJhbCBpbmRpY2VzIGhhdmUgYmVlbiBwcm9wb3NlZCBzbyBmYXIgYnV0IHdlIGZvY3VzIGhlcmUgb24gdGhlIGV2b2x1dGlvbmFyeSBkaXN0aW5jdGl2ZW5lc3MgaW5kZXggY2FsbGVkIOKAmEZhaXIgUHJvcG9ydGlvbuKAmSBhcyBwcm9wb3NlZCBieSBAUmVkZGluZzIwMDMgYW5kIEBJc2FhYzIwMDcuIAoKIyMjIyBFdm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzIChyaWNobmVzcyBpbmRpY2VzKQokRUQkLCBldm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzIGlzIGEgcmljaG5lc3MgaW5kaWNlcy4gTk9URTogbm90IGVxdWFsIHRvIEZhaXRoJ3MgUEQgYmVjYXVzZSB0aGUgJEVEX3tpfSQgYXJlIGNvbXB1dGVkIGZyb20gdGhlIHJlZ2lvbmFsIHBvb2wgb2Ygc3BlY2llcyBhbmQgc3VtZWQgYWNyb3NzIGEgZ2l2ZW4gYXNzZW1ibGFnZSAoaS5lLiBhIHN1YnNldCBvZiB0aGUgcmVnaW9uYWwgc3BlY2llcyBwb29sKSBbQFR1Y2tlcjIwMTY7IEBTYWZpMjAxM2E7IEBSZWRkaW5nMjAwMzsgQElzYWFjMjAwN10uIAoKJCQKICBFRCA9IFxzdW1fe2l9RURfe2l9IFxcCiAgXCBcXCAKICB3aGVyZSBcIEVEX3tpfSA9IFxzdW1fe2IgXGluIEJfe3Rfe2l9fX0gXGRmcmFje0xfe2J9fXtTX3tifX0gCiQkCgokQUVEJCwgQWJ1bmRhbmNlLXdlaWdodGVkICRFRCQgW0BUdWNrZXIyMDE2OyBAQ2Fkb3R0ZTIwMTBdLiAKJCQKXHN1bV97aX0gQUVEX3tpfSBcXApcIFxcCndoZXJlIFwgQUVEX3tpfSA9IFxzdW1fe2IgXGluIEJfe3Rfe2l9fX0gXGRmcmFje0xfe2J9fXtBX3tifSB9KiBwX3tpfQokJAoKCgpgYGB7cn0KCiMgQnJ1bm8ncyBmdW5jdGlvbiBmb3IgRUQuIFByb3ZpZGVkIGluIGxpYnJhcnkoRkFSTSkKCmV2b2wuZGlzdGluY3QyIDwtIGZ1bmN0aW9uICh0cmVlLCB0eXBlID0gYygiZXF1YWwuc3BsaXRzIiwgImZhaXIucHJvcG9ydGlvbiIpLCAKICAgIHNjYWxlID0gRkFMU0UsIHVzZS5icmFuY2gubGVuZ3RocyA9IFRSVUUpIAp7CiAgICB0eXBlIDwtIG1hdGNoLmFyZyh0eXBlKQogICAgaWYgKGlzLnJvb3RlZCh0cmVlKSA9PSBGQUxTRSkgCiAgICAgICAgd2FybmluZygiQSByb290ZWQgcGh5bG9nZW55IGlzIHJlcXVpcmVkIGZvciBtZWFuaW5nZnVsIG91dHB1dCBvZiB0aGlzIGZ1bmN0aW9uIiwgCiAgICAgICAgICAgIGNhbGwuID0gRkFMU0UpCiAgICBpZiAoc2NhbGUgPT0gVFJVRSkgewogICAgICAgIGlmIChpcy51bHRyYW1ldHJpYyh0cmVlKSA9PSBUUlVFKSAKICAgICAgICAgICAgdHJlZSRlZGdlLmxlbmd0aCA8LSB0cmVlJGVkZ2UubGVuZ3RoLyhhcy5udW1lcmljKGJyYW5jaGluZy50aW1lcyh0cmVlKVsxXSkpCiAgICAgICAgZWxzZSB0cmVlJGVkZ2UubGVuZ3RoIDwtIHRyZWUkZWRnZS5sZW5ndGgvc3VtKHRyZWUkZWRnZS5sZW5ndGgpCiAgICB9CiAgICBpZiAodXNlLmJyYW5jaC5sZW5ndGhzID09IEZBTFNFKSAKICAgICAgICB0cmVlJGVkZ2UubGVuZ3RoIDwtIHJlcCgxLCBsZW5ndGgodHJlZSRlZGdlLmxlbmd0aCkpCiAgICBmb3IgKGkgaW4gMTpsZW5ndGgodHJlZSR0aXAubGFiZWwpKSB7CiAgICAgICAgc3BwIDwtIHRyZWUkdGlwLmxhYmVsW2ldCiAgICAgICAgbm9kZXMgPC0gLmdldC5ub2Rlcyh0cmVlLCBzcHApCiAgICAgICAgbm9kZXMgPC0gbm9kZXNbMToobGVuZ3RoKG5vZGVzKSAtIDEpXQogICAgICAgIGludGVybmFsLmJybGVuIDwtIHRyZWUkZWRnZS5sZW5ndGhbd2hpY2godHJlZSRlZGdlWywgCiAgICAgICAgICAgIDJdICVpbiUgbm9kZXMpXQogICAgICAgIGlmIChsZW5ndGgoaW50ZXJuYWwuYnJsZW4pICE9IDApIHsKICAgICAgICAgICAgaW50ZXJuYWwuYnJsZW4gPC0gaW50ZXJuYWwuYnJsZW4gKiBzd2l0Y2godHlwZSwgZXF1YWwuc3BsaXRzID0gc29ydChyZXAoMC41LCAKICAgICAgICAgICAgICAgIGxlbmd0aChpbnRlcm5hbC5icmxlbikpXmMoMTpsZW5ndGgoaW50ZXJuYWwuYnJsZW4pKSksIAogICAgICAgICAgICAgICAgZmFpci5wcm9wb3J0aW9uID0gewogICAgICAgICAgICAgICAgICBmb3IgKGogaW4gMTpsZW5ndGgobm9kZXMpKSB7CiAgICAgICAgICAgICAgICAgICAgc29ucyA8LSAubm9kZS5kZXNjKHRyZWUsIG5vZGVzW2pdKQogICAgICAgICAgICAgICAgICAgIG4uZGVzY2VuZGVudHMgPC0gbGVuZ3RoKHNvbnMkdGlwcykKICAgICAgICAgICAgICAgICAgICBpZiAoaiA9PSAxKSBwb3J0aW9uIDwtIG4uZGVzY2VuZGVudHMgZWxzZSBwb3J0aW9uIDwtIGMobi5kZXNjZW5kZW50cywgCiAgICAgICAgICAgICAgICAgICAgICBwb3J0aW9uKQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIDEvcG9ydGlvbgogICAgICAgICAgICAgICAgfSkKICAgICAgICB9CiAgICAgICAgRUQgPC0gc3VtKGludGVybmFsLmJybGVuLCB0cmVlJGVkZ2UubGVuZ3RoW3doaWNoLmVkZ2UodHJlZSwgCiAgICAgICAgICAgIHNwcCldKQogICAgICAgIGlmIChpID09IDEpIAogICAgICAgICAgICB3IDwtIEVECiAgICAgICAgZWxzZSB3IDwtIGModywgRUQpCiAgICB9CiAgICByZXR1cm4odykKfQoKYGBgCgpFdm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzIGlzIG91ciBiYXNpYyBtZWFzdXJlIG9mIHBoeWxvZ2VuZXRpYyBpc29sYXRpb24uICNUaGlzIHNob3VsZCBsaWtlbHkgYmUgJ2ZhaXIgcHJvcG9ydGlvbnMnIGluc3RlYWQgb2YgJ2VxdWFsLnNwbGl0cycuCgoKYGBge3J9CgojIENhbGN1bGF0ZSBFRAojIFVzaW5nIGVxdWFsLnNwbGl0cyBtZXRob2QsIGZhc3RlciBjb21wdXRhdGlvbgojIEV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3NfaSA8LSBldm9sLmRpc3RpbmN0Mih0aGlzX3RyZWUsIHR5cGUgPSAiZXF1YWwuc3BsaXRzIikgIAoKIyBFRCAtIFN1bW1lZCBldm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzCiMgRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzc19zdW0gPC0gc3VtKEV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3NfaSkKYGBgCgoKYGBge3J9CiNFdm9sdXRpb25hcnlfZGlzdGluY3RpdmVuZXNzX3N1bQpgYGAKCgoKV2UgY2FuIHJ1biBzb21lIHN0YW5kYXJkIHN1bW1hcnkgc3RhdGlzdGljcyAobWVhbiBhbmQgdmFyaWFuY2UpIG9uIHRoaXMgRUQgbWVhc3VyZS4gdmFyKEVkKSBzaG93cyB1cCBjbG9zZSB0byBWUEQgb24gdGhlIFBDQXMgaW4gdGhlIGludHJvIFtAVHVja2VyMjAxNl0uCgpgYGB7cn0KIyBtZWFuKEVEKQojIG1lYW5fUGh5bG9nZW5ldGljX2lzb2xhdGlvbiA8LSBtZWFuKEV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3NfaSkKCiMgdmFyKEVEKQojdmFyaWFuY2VfUGh5bG9nZW5ldGljX2lzb2xhdGlvbiA8LSB2YXIoRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzc19pKQpgYGAKCgoKYGBge3J9CiNtZWFuX1BoeWxvZ2VuZXRpY19pc29sYXRpb24KI3ZhcmlhbmNlX1BoeWxvZ2VuZXRpY19pc29sYXRpb24KYGBgCgojIyMjIE1lYW4gZXZvbHV0aW9uYXJ5IGRpc3RpbmN0aXZlbmVzcyAoZGl2ZXJnZW5jZSBpbmRpY2VzKQpUaGUgZGl2ZXJnZW5jZSBpbmRpY2VzIHZlcnNpb24gZm9yICRFRCQgaXMgbWVhbiBldm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzLCAkTUVEJC4gVGhlIG1lYW4gb2YgZXZvbHV0aW9uYXJ5IGRpc3RpbmN0aXZlbmVzcyBbQFJlZGRpbmcyMDAzOyBASXNhYWMyMDA3XS4gCiQkCk1FRCA9IFxkZnJhYwp7XHN1bV97aX0gRURfe2l9fQp7U30gXFwKXCBcXAp3aXRoIFxcClwgXFwKRURfe2l9ID0gXHN1bV97YiBcaW4gQl97dF97aX19fSBcZGZyYWN7TF97Yn19e1Nfe2J9fQokJAojIyMjIEVudHJvcHkgbWVhc3VyZSBvZiBldm9sdXRvbmFyeSBkaXN0aW5jdGl2ZW5lc3MgKHJlZ3VsYXJpdHkgaW5kaWNlcykKVGhlIHJlZ3VsYXJpdHkgaW5kaWNlcyBmb3IgJEVEJC9waHlsb2dlbmV0aWMgaXNvbGF0aW9uIGFyZSAkSF97RUR9JCwgJEVfe0VEfSQsICR2YXIoRUQpJCwgJEhfe0FFRH0kCgokSF97RUR9JCwgRW50cm9weSBtZWFzdXJlIG9mIGV2b2x1dGlvbmFyeSBkaXN0aW5jdGl2ZW5lc3MsIGlzIHRoZSBzaGFubm9uIGluZGV4IGFwcGxpZWQgdG8gZXZvbHV0aW9uYXJ5IGRpc3RpbmN0aXZlbmVzcyB2YWx1ZXMgW0BDYWRvdHRlMjAxMF0uIAokJApIX3tFRH0gPSAtXHN1bV97aT0xfV57U30KKChcZGZyYWN7RURfe2l9fXtcc3VtX3tpPTF9XntTfSBFRF97aX19KQoqIFxsbiAoXGRmcmFje0VEX3tpfX17XHN1bV97aT0xfV57U30gRURfe2l9fSkpCiQkCgokRV97RUR9JCwgRXF1aXRhYmlsaXR5IG9mIGV2b2x1dGlvbmFyeSBkaXN0aW5jdGl2ZW5lc3MsIGlzICRIX3tFRH0kIGNvbnRyb2xsZWQgZm9yIHNwZWNpZXMgcmljaG5lc3MgW0BDYWRvdHRlMjAxMF0uIAoKJCQKRV97RUR9ID0gXGRmcmFje0hfe0VEfX17XGxuKFMpfQokJAokdmFyKEVEKSQsIFZhcmlhbmNlIGluIGV2b2x1dGlub2FyeSBkaXN0aW5jdGl2ZW5lc3MsIGlzIHRoZSB2YXJpYW5jZSBvZiBzcGVjaWVzIGV2b2x1dGlvbmFyeSBkaXN0aW5jdGl2ZW5lc3MgW0BUdWNrZXIyMDE2XS4gCgokJAp2YXIoRUQpID0gXGRmcmFjezF9e1MtMX0gKgpcc3VtX3tpPTF9XntTfQooRURfe2l9LVxkZnJhY3tcc3VtX3tpPTF9XntTfSBFRF97aX19e1N9KV4yCiQkCiRIX3tFRF97QWJ9fSQsIEFidW5kYW5jZS13ZWlnaHRlZCB2ZXJzaW9uIG9mICRIX3tFRH0kIFtAQ2Fkb3R0ZTIwMTBdLgoKJCQKSF97RURfe0FifX0gPSAtXHN1bV97aT0xfV57U30KKFxkZnJhY3tuX3tpfUFFRF97aX19e1xzdW1fe2k9MX1ee1N9IG5fe2l9QUVEX3tpfX0gKgpcbG4oXGRmcmFje25fe2l9QUVEX3tpfX17XHN1bV97aT0xfV57U30gbl97aX1BRURfe2l9fSkpCiQkCgoKIyMgQmV0YSBkaXZlcnNpdHkKV2UgY3VycmVudGx5IGFyZSBub3QgdXNpbmcgYW55IGJldGEgZGl2ZXJzaXR5IG1ldHJpY3MgYnV0IHRoZXJlIGFyZSBtYW55IHRvIGNob29zZSBmcm9tIGlmIHdlIGRlY2lkZSB0byBhZGQgdGhlbSBsYXRlci4gCgoKCiMjIFRyZWUgdG9wb2xvZ3kKVHJlZSB0b3BvbG9neSBpcyBhIG1lYXN1cmUgb2YgdGhlIHNoYXBlIG9mIHRoZSBvdmVyYWxsIHRyZWUuIFRoZSB0cmVlIGNhbiBiZSBsb3BzaWRlZCBzaWRlLXRvLXNpZGUgb3IgZnJvbnQtdG8tYmFjay4gCgpPdXIgbW9zdCB0cnVzdGVkIGluZGV4IGZvciB0aGUgdGlwcHkgdnMgdHJ1bmt5IG9mIGEgdHJlZSBpcyB0aGUgZ2FtbWEgaW5kZXgsICRcZ2FtbWEkLlRoZSBpbmRleCBjaGFyYWN0ZXJpemVzIHRoZSBkaXN0cmlidXRpb24gb2YgYnJhbmNoaW5nIGV2ZW50cyB3aXRoaW4gdGhlIHRyZWUuIFRyZWVzIHdpdGggzrMgPCAwIGhhdmUgcmVsYXRpdmVseSBsb25nZXIgYnJhbmNoZXMgdG93YXJkcyB0aGUgdGlwcyBvZiB0aGUgcGh5bG9nZW55ICh0aXBweSB0cmVlcyksIHdoZXJlYXMgdHJlZXMgd2l0aCDOsyA+IDAgaGF2ZSByZWxhdGl2ZWx5IGxvbmdlciBpbnRlci1ub2RhbCBkaXN0YW5jZXMgdG93YXJkcyB0aGUgcm9vdCBvZiB0aGUgcGh5bG9nZW55IChzdGVtbXkgdHJlZXMpLiAgdGsgcmVwcmVzZW50cyBhbiDigJhldm9sdXRpb25hcnkgcGVyaW9k4oCZIChsaW1pdHMgYXJlIGdpdmVuIGJ5IHR3byBzcGVjaWF0aW9uIGV2ZW50cykgb3IgZXF1aXZhbGVudGx5IGFuIGludGVybm9kZSBkaXN0YW5jZSBbQFB5YnVzMjAwMF0uIAoKJCQKICBcZ2FtbWEgPSBcZGZyYWMKICB7KFxkZnJhY3sxfXtTLTJ9KiBcc3VtX3tpPTJ9XntTLTF9IChcc3VtX3trPTJ9XntpfSBLdF97a30pKS0gXGRmcmFjezF9ezJ9ICogXHN1bV97aj0yfV57U30ganRfe2p9fQogIHsoXHN1bV97aj0yfV57U30ganRfe2p9KSAqIFxzcXJ0e1xkZnJhY3sxfXsxMiooUy0yKX19fQokJAoKCmBgYHtyfQojIGx0dCBmdW5jdGlvbiBmcm9tIGxpYnJhcnkocGh5dG9vbHMpCmx0dCA8LSBmdW5jdGlvbiAodHJlZSwgcGxvdCA9IFRSVUUsIGRyb3AuZXh0aW5jdCA9IEZBTFNFLCBsb2cubGluZWFnZXMgPSBUUlVFLCAKICAgIGdhbW1hID0gVFJVRSwgLi4uKSAKewogICAgdG9sIDwtIDFlLTA2CiAgICBpZiAoIWluaGVyaXRzKHRyZWUsICJwaHlsbyIpICYmICFpbmhlcml0cyh0cmVlLCAibXVsdGlQaHlsbyIpKSAKICAgICAgICBzdG9wKCJ0cmVlIG11c3QgYmUgb2JqZWN0IG9mIGNsYXNzIFwicGh5bG9cIiBvciBcIm11bHRpUGh5bG9cIi4iKQogICAgaWYgKGluaGVyaXRzKHRyZWUsICJtdWx0aVBoeWxvIikpIHsKICAgICAgICBvYmogPC0gbGFwcGx5KHRyZWUsIGx0dCwgcGxvdCA9IEZBTFNFLCBkcm9wLmV4dGluY3QgPSBkcm9wLmV4dGluY3QsIAogICAgICAgICAgICBsb2cubGluZWFnZXMgPSBsb2cubGluZWFnZXMsIGdhbW1hID0gZ2FtbWEpCiAgICAgICAgY2xhc3Mob2JqKSA8LSAibXVsdGlMdHQiCiAgICB9CiAgICBlbHNlIHsKICAgICAgICB0cmVlIDwtIHJlb3JkZXIucGh5bG8odHJlZSwgb3JkZXIgPSAiY2xhZGV3aXNlIikKICAgICAgICBpZiAoIWlzLm51bGwodHJlZSRub2RlLmxhYmVsKSkgewogICAgICAgICAgICBub2RlLm5hbWVzIDwtIHNldE5hbWVzKHRyZWUkbm9kZS5sYWJlbCwgMTp0cmVlJE5ub2RlICsgCiAgICAgICAgICAgICAgICBOdGlwKHRyZWUpKQogICAgICAgICAgICB0cmVlJG5vZGUubGFiZWwgPC0gTlVMTAogICAgICAgIH0KICAgICAgICBlbHNlIG5vZGUubmFtZXMgPC0gTlVMTAogICAgICAgIGlmIChpcy51bHRyYW1ldHJpYyh0cmVlKSkgewogICAgICAgICAgICBoIDwtIG1heChub2RlSGVpZ2h0cyh0cmVlKSkKICAgICAgICAgICAgdGltZSA8LSBjKDAsIGggLSBzb3J0KGJyYW5jaGluZy50aW1lcyh0cmVlKSwgZGVjcmVhc2luZyA9IFRSVUUpLCAKICAgICAgICAgICAgICAgIGgpCiAgICAgICAgICAgIG5vZGVzIDwtIGFzLm51bWVyaWMobmFtZXModGltZSlbMjoobGVuZ3RoKHRpbWUpIC0gCiAgICAgICAgICAgICAgICAxKV0pCiAgICAgICAgICAgIGx0dCA8LSBjKGN1bXN1bShjKDEsIHNhcHBseShub2RlcywgZnVuY3Rpb24oeCwgeSkgc3VtKHkgPT0gCiAgICAgICAgICAgICAgICB4KSAtIDEsIHkgPSB0cmVlJGVkZ2VbLCAxXSkpKSwgbGVuZ3RoKHRyZWUkdGlwLmxhYmVsKSkKICAgICAgICAgICAgbmFtZXMobHR0KSA8LSBuYW1lcyh0aW1lKQogICAgICAgIH0KICAgICAgICBlbHNlIHsKICAgICAgICAgICAgZHJvcC5leHRpbmN0LnRpcHMgPC0gZnVuY3Rpb24ocGh5KSB7CiAgICAgICAgICAgICAgICB0ZW1wIDwtIGRpYWcodmN2KHBoeSkpCiAgICAgICAgICAgICAgICBpZiAobGVuZ3RoKHRlbXBbdGVtcCA8IChtYXgodGVtcCkgLSB0b2wpXSkgPiAKICAgICAgICAgICAgICAgICAgMCkgCiAgICAgICAgICAgICAgICAgIHBydW5lZC5waHkgPC0gZHJvcC50aXAocGh5LCBuYW1lcyh0ZW1wW3RlbXAgPCAKICAgICAgICAgICAgICAgICAgICAobWF4KHRlbXApIC0gdG9sKV0pKQogICAgICAgICAgICAgICAgZWxzZSBwcnVuZWQucGh5IDwtIHBoeQogICAgICAgICAgICAgICAgcmV0dXJuKHBydW5lZC5waHkpCiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGRyb3AuZXh0aW5jdCA9PSBUUlVFKSAKICAgICAgICAgICAgICAgIHRyZWUgPC0gZHJvcC5leHRpbmN0LnRpcHModHJlZSkKICAgICAgICAgICAgcm9vdCA8LSBsZW5ndGgodHJlZSR0aXApICsgMQogICAgICAgICAgICBub2RlLmhlaWdodCA8LSBtYXRyaXgoTkEsIG5yb3codHJlZSRlZGdlKSwgMikKICAgICAgICAgICAgZm9yIChpIGluIDE6bnJvdyh0cmVlJGVkZ2UpKSB7CiAgICAgICAgICAgICAgICBpZiAodHJlZSRlZGdlW2ksIDFdID09IHJvb3QpIHsKICAgICAgICAgICAgICAgICAgbm9kZS5oZWlnaHRbaSwgMV0gPC0gMAogICAgICAgICAgICAgICAgICBub2RlLmhlaWdodFtpLCAyXSA8LSB0cmVlJGVkZ2UubGVuZ3RoW2ldCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgbm9kZS5oZWlnaHRbaSwgMV0gPC0gbm9kZS5oZWlnaHRbbWF0Y2godHJlZSRlZGdlW2ksIAogICAgICAgICAgICAgICAgICAgIDFdLCB0cmVlJGVkZ2VbLCAyXSksIDJdCiAgICAgICAgICAgICAgICAgIG5vZGUuaGVpZ2h0W2ksIDJdIDwtIG5vZGUuaGVpZ2h0W2ksIDFdICsgdHJlZSRlZGdlLmxlbmd0aFtpXQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGx0dCA8LSB2ZWN0b3IoKQogICAgICAgICAgICB0cmVlLmxlbmd0aCA8LSBtYXgobm9kZS5oZWlnaHQpCiAgICAgICAgICAgIG4uZXh0aW5jdCA8LSBzdW0obm9kZS5oZWlnaHRbdHJlZSRlZGdlWywgMl0gPD0gbGVuZ3RoKHRyZWUkdGlwKSwgCiAgICAgICAgICAgICAgICAyXSA8ICh0cmVlLmxlbmd0aCAtIHRvbCkpCiAgICAgICAgICAgIG5vZGUuaGVpZ2h0W3RyZWUkZWRnZVssIDJdIDw9IGxlbmd0aCh0cmVlJHRpcCksIDJdIDwtIG5vZGUuaGVpZ2h0W3RyZWUkZWRnZVssIAogICAgICAgICAgICAgICAgMl0gPD0gbGVuZ3RoKHRyZWUkdGlwKSwgMl0gKyAxLjEgKiB0b2wKICAgICAgICAgICAgdGltZSA8LSBjKDAsIG5vZGUuaGVpZ2h0WywgMl0pCiAgICAgICAgICAgIG5hbWVzKHRpbWUpIDwtIGFzLmNoYXJhY3RlcihjKHJvb3QsIHRyZWUkZWRnZVssIDJdKSkKICAgICAgICAgICAgdGVtcCA8LSB2ZWN0b3IoKQogICAgICAgICAgICB0aW1lIDwtIHRpbWVbb3JkZXIodGltZSldCiAgICAgICAgICAgIHRpbWUgPC0gdGltZVsxOih0cmVlJE5ub2RlICsgbi5leHRpbmN0ICsgMSldCiAgICAgICAgICAgIGZvciAoaSBpbiAxOihsZW5ndGgodGltZSkgLSAxKSkgewogICAgICAgICAgICAgICAgbHR0W2ldIDwtIDAKICAgICAgICAgICAgICAgIGZvciAoaiBpbiAxOm5yb3cobm9kZS5oZWlnaHQpKSBsdHRbaV0gPC0gbHR0W2ldICsgCiAgICAgICAgICAgICAgICAgICh0aW1lW2ldID49IChub2RlLmhlaWdodFtqLCAxXSAtIHRvbCkgJiYgdGltZVtpXSA8PSAKICAgICAgICAgICAgICAgICAgICAobm9kZS5oZWlnaHRbaiwgMl0gLSB0b2wpKQogICAgICAgICAgICB9CiAgICAgICAgICAgIGx0dFtpICsgMV0gPC0gMAogICAgICAgICAgICBmb3IgKGogaW4gMTpucm93KG5vZGUuaGVpZ2h0KSkgbHR0W2kgKyAxXSA8LSBsdHRbaSArIAogICAgICAgICAgICAgICAgMV0gKyAodGltZVtpICsgMV0gPD0gKG5vZGUuaGVpZ2h0W2osIDJdICsgdG9sKSkKICAgICAgICAgICAgbmFtZXMobHR0KSA8LSBuYW1lcyh0aW1lKQogICAgICAgICAgICBsdHQgPC0gYygxLCBsdHQpCiAgICAgICAgICAgIHRpbWUgPC0gYygwLCB0aW1lKQogICAgICAgICAgICB0aW1lW2xlbmd0aCh0aW1lKV0gPC0gdGltZVtsZW5ndGgodGltZSldIC0gMS4xICogCiAgICAgICAgICAgICAgICB0b2wKICAgICAgICB9CiAgICAgICAgaWYgKCFpcy5udWxsKG5vZGUubmFtZXMpKSB7CiAgICAgICAgICAgIG5uIDwtIHNhcHBseShuYW1lcyh0aW1lKSwgZnVuY3Rpb24oeCwgeSkgaWYgKGFueShuYW1lcyh5KSA9PSAKICAgICAgICAgICAgICAgIHgpKSAKICAgICAgICAgICAgICAgIHlbd2hpY2gobmFtZXMoeSkgPT0geCldCiAgICAgICAgICAgIGVsc2UgIiIsIHkgPSBub2RlLm5hbWVzKQogICAgICAgICAgICBuYW1lcyhsdHQpIDwtIG5hbWVzKHRpbWUpIDwtIG5uCiAgICAgICAgfQogICAgICAgIGlmIChnYW1tYSA9PSBGQUxTRSkgewogICAgICAgICAgICBvYmogPC0gbGlzdChsdHQgPSBsdHQsIHRpbWVzID0gdGltZSwgdHJlZSA9IHRyZWUpCiAgICAgICAgICAgIGNsYXNzKG9iaikgPC0gImx0dCIKICAgICAgICB9CiAgICAgICAgZWxzZSB7CiAgICAgICAgICAgIGdhbSA8LSBnYW1tYXRlc3QobGlzdChsdHQgPSBsdHQsIHRpbWVzID0gdGltZSkpCiAgICAgICAgICAgIG9iaiA8LSBsaXN0KGx0dCA9IGx0dCwgdGltZXMgPSB0aW1lLCBnYW1tYSA9IGdhbSRnYW1tYSwgCiAgICAgICAgICAgICAgICBwID0gZ2FtJHAsIHRyZWUgPSB0cmVlKQogICAgICAgICAgICBjbGFzcyhvYmopIDwtICJsdHQiCiAgICAgICAgfQogICAgfQogICAgaWYgKHBsb3QpIAogICAgICAgIHBsb3Qob2JqLCBsb2cubGluZWFnZXMgPSBsb2cubGluZWFnZXMsIC4uLikKICAgIG9iagp9CjxlbnZpcm9ubWVudDogbmFtZXNwYWNlOnBoeXRvb2xzPgpgYGAKCgoKYGBge3J9Cmx0dHMgPC0gbHR0KHRoaXNfdHJlZSwgZ2FtbWEgPSBUUlVFLCBwbG90ID0gRkFMU0UpCmx0dHMKc3RyKGx0dHMpCmBgYAoKCgoKYGBge3J9CmxpbmVhZ2VzX3Rocm91Z2hfdGltZSA8LSBhcy5udW1lcmljKGx0dHNbWzFdXSkKdGltZV9zdGVwcyA8LSBhcy5udW1lcmljKGx0dHNbWzJdXSkKI2V4dHJhY3QgR2FtbWEgaW5kZXgKZ2FtbWEgPC0gbHR0c1tbM11dCmdhbW1hX3BfdmFsdWUgPC0gbHR0c1tbNF1dCmBgYAoKCmBgYHtyfQpsaW5lYWdlc190aHJvdWdoX3RpbWUgCnRpbWVfc3RlcHMgCmdhbW1hIApnYW1tYV9wX3ZhbHVlIApgYGAKCgpUaGVyZSBhcmUgdHdvIG90aGVyIHJlZ3VsYXJseSB1c2VkIG1ldHJpY3MgdGhhdCBpbmNsdWRlIGFidW5kYW5jZSBtZWFzdXJlcy4gTm90ZTogd2UgZG9uJ3QgaGF2ZSBhYnVuZGFuY2UgbWVhc3VyZXMgZm9yIEQtcGxhY2UgZGF0YS4gCgokSUFDJCwgaW1iYWxhbmNlIG9mIGFidW5kYW5jZSBhdCB0aGUgY2xhZGUgbGV2ZWwsIHF1YW50aWZpZXMgdGhlIHJlbGF0aXZlIGRldmlhdGlvbiBpbiB0aGUgYWJ1bmRhbmNlIGRpc3RyaWJ1dGlvbiBmcm9tIGEgbnVsbCBjYXNlIHdoZXJlIGluZGl2aWR1YWxzIGFyZSBldmVubHkgcGFydGl0aW9uZWQgYmV0d2VlbiBjbGFkZSBzcGxpdHMuICR2JCBpcyB0aGUgbnVtYmVyIG9mIG5vZGVzIGluIHRoZSBwaHlsb2dlbmV0aWMgdHJlZS4gICRuX3tpfSQgaXMsIGFzIGRlZmluZWQgYWJvdmUsIHRoZSBhYnVuZGFuY2Ugb2Ygc3BlY2llcyAkaSQgaW4gdGhlIGFzc2VtYmxhZ2UuICAkXGV0YV97a30kIGlzIHRoZSBleHBlY3RlZCBhYnVuZGFuY2Ugc3BlY2llcyAkaSQgd291bGQgaGF2ZSBpZiB0aGUgYWJ1bmRhbmNlIHdhcyByYW5kb21seSBzcGxpdCBhbW9uZyBsaW5lYWdlcyBpbiB0aGUgcGh5bG9nZW5ldGljIHRyZWUgYXQgZWFjaCBzcGVjaWF0aW9uIGV2ZW50LiAgaXMgdGhlIG51bWJlciBvZiBsaW5lYWdlcyBvcmlnaW5hdGluZyBhdCBub2RlICRrJCBpbiB0aGUgc2V0ICRzKGsscm9vdCkkLCB3aGljaCBjb250YWlucyB0aGUgbm9kZXMgbG9jYXRlZCBvbiB0aGUgcGF0aCBiZXR3ZWVuIG5vZGUgJGskIGFuZCB0aGUgcm9vdCBvZiB0aGUgcGh5bG9nZW5ldGljIHRyZWUuIE4gaXMgdGhlIHRvdGFsIGFzc2VtYmxhZ2UgYWJ1bmRhbmNlIFtAQ2Fkb3R0ZTIwMTBdLiAKCiQkClxkZnJhY3tcc3VtX3tpPTF9XntTfSAgfG5fe2l9IC0gXGhhdHtuX3tpfX18fQp7dn0gXFwKXCBcXAp3aGVyZSBcXCAKXCBcXApcaGF0e25fe2l9fSA9IFxkZnJhY3tOfXtccHJvZF97SyBcaW4gcyhpLCByb290KX1cZXRhX3trfX0KJCQKCiRJX3tjfSQsIHRoZSBDb2xsZXNzIGluZGV4LCBpcyB0aGUgc3VtIG9mIHRoZSBhYnNvbHV0ZSBkaWZmZXJlbmNlcyBpbiBzcGVjaWVzIHJpY2huZXNzIGJldHdlZW4gc2lzdGVyLWNsYWRlcyBhdCBlYWNoIGludGVybmFsIG5vZGUuIEZvciBmdWxseSByZXNvbHZlZCB0cmVlcywgZWFjaCBpbnRlcm5hbCBub2RlIGRlZmluZXMgdHdvIHNpc3Rlci1jbGFkZXMuICRTX3sxa30kIGlzIHRoZSBudW1iZXIgb2Ygc3BlY2llcyBkZXNjZW5kaW5nIGZyb20gdGhlIGZpcnN0IGNsYWRlIGRlZmluZWQgYnkgbm9kZSBrIGFuZCAkU197Mmt9JCB0aGF0IG9mIHRoZSBzZWNvbmQgY2xhZGUuICR2JCBpcywgYXMgZGVmaW5lZCBhYm92ZSwgdGhlIG51bWJlciBvZiBub2RlcyBpbiB0aGUgcGh5bG9nZW5ldGljIFtAQ29sbGVzczE5ODJdLiAKCiQkCklfe2N9ID0gXHN1bV97az0xfV57dn0gfFNfezFrfSAtIFNfezJrfXwKJCQKCgoKCiMjIE1hY3JvZXZvbHV0aW9uYXJ5IHJhdGVzCgpgYGB7cn0KCiNmdW5jdGlvbiBuYW1lID0gYmQsIGZ1bmN0aW9uIGlucHV0ID0gdHJlZSBvZiB0eXBlICdwaHlsbycKYmQgPC0gZnVuY3Rpb24gKHRyZWUpIAp7CiAgICB0cmVlJGVkZ2UubGVuZ3RoIDwtIHRyZWUkZWRnZS5sZW5ndGgvbWF4KHRyZWUkZWRnZS5sZW5ndGgpCiAgICB4IDwtIGJpcnRoZGVhdGgodHJlZSkKICAgIGIgPC0geCRwYXJhWzJdLygxIC0geCRwYXJhWzFdKQogICAgZCA8LSBiIC0geCRwYXJhWzJdCiAgICBjKHNldE5hbWVzKGMoYiwgZCksIGMoImIiLCAiZCIpKSwgeCRwYXJhKQp9CjxlbnZpcm9ubWVudDogbmFtZXNwYWNlOkZBUk0+CgpgYGAKCgoKYGBge3J9CiAjIyBTcGVjaWF0aW9uIHZzIGV4dGluY3Rpb24gcmF0ZXMgYW5kIE5ldCBkaXZlcnNpZmljYXRpb24KYmRzIDwtIGJkKHRoaXNfdHJlZSkKc3BlY2lhdGlvbl9yYXRlIDwtIGJkc1sxXQpleHRpbmN0aW9uX3JhdGUgPC0gYmRzWzJdCmV4dGluY3Rpb25fcGVyX3NwZWNpYXRpb24gPC0gYmRzWzNdCnNwZWNpYXRpb25fbWludXNfZXh0aW5jdGlvbiA8LSBiZHNbNF0KICAKYGBgCgoKYGBge3J9CiMjIFNwZWNpYXRpb24gdnMgZXh0aW5jdGlvbiByYXRlcyBhbmQgTmV0IGRpdmVyc2lmaWNhdGlvbiBkZXBlbmRlbnQgb24gdHJhaXQKIyBOLmZvci5kb20gPC0gdGFibGUodGhpc193b3JsZFssIDZdKQojICAgIGlmKGxlbmd0aChOLmZvci5kb20pID09IDIpIHsKcGFyLmRpdi5kZXAgPC0gRGl2RGVwKCBteXRyZWUgPSB0aGlzX3RyZWUsIG15V29ybGQgPSB0aGlzX3dvcmxkKQp0cmFpdF8xX3NwZWNpYXRpb24gPC0gcGFyLmRpdi5kZXBbMV0KdHJhaXRfMl9zcGVjaWF0aW9uIDwtIHBhci5kaXYuZGVwWzJdCnRyYWl0XzFfZXh0aW5jdGlvbiA8LSBwYXIuZGl2LmRlcFszXQp0cmFpdF8yX2V4dGluY3Rpb24gPC0gcGFyLmRpdi5kZXBbNF0KdHJhbnNpdGlvbl9mcm9tX3RyYWl0XzFfdG9fMiA8LSBwYXIuZGl2LmRlcFs1XQp0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMl90b18xIDwtIHBhci5kaXYuZGVwWzZdCnRyYW5zaXRpb25fcmF0ZV9yYXRpb18xdG8yX292ZXJfMnRvMSA8LSB0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMV90b18yL3RyYW5zaXRpb25fZnJvbV90cmFpdF8yX3RvXzEKICAgICAgCmBgYAoKCgoKYGBge3J9CgojIyBDcm93biBhZ2UgcGVyIHRyYWl0IEFVQyBhbmQgZWZmZWN0IHNpemUKdGlwLmxlbmd0aCA8LSB0aGlzX3RyZWUkZWRnZS5sZW5ndGhbdGhpc190cmVlJGVkZ2VbLCAyXSAlaW4lIDE6TnRpcCh0aGlzX3RyZWUpXQp0aXAubGVuZ3RoIDwtICh0aXAubGVuZ3RoIC0gbWluKHRpcC5sZW5ndGgpKSAvIChtYXgodGlwLmxlbmd0aCkgLSBtaW4odGlwLmxlbmd0aCkpCnRoaXNfdHJhaXQgPC0gdGhpc193b3JsZFttYXRjaCh0aGlzX3RyZWUkdGlwLmxhYmVsLCB0aGlzX3dvcmxkWywgOF0pLCA2XQp0aXAubGVuZ3RoLjIgPC0gdGlwLmxlbmd0aFt0aGlzX3RyYWl0ID09IDJdCnRpcC5sZW5ndGguMSA8LSB0aXAubGVuZ3RoW3RoaXNfdHJhaXQgPT0gMV0KbW9kZWwgPC0gZ2xtKGFzLmZhY3Rvcih0aGlzX3RyYWl0KSB+IGxvZyh0aXAubGVuZ3RoICsgMSksCiAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiKQplZmZlY3Quc2l6ZSA8LSBtb2RlbCRjb2VmZmljaWVudHNbMl0KIyBwbG90KHkgPSB0aGlzX3RyYWl0IC0gMSwgeD0gbG9nKHRpcC5sZW5ndGgpKQpwIDwtIHByZWRpY3QobW9kZWwsIGFzLmZhY3Rvcih0aGlzX3RyYWl0KSwgdHlwZSA9ICJyZXNwIikKIyBwb2ludHMoeSA9IHAsIHggPSBsb2codGlwLmxlbmd0aCksIGNvbCA9ICJyZWQiKQpwciA8LSBwcmVkaWN0aW9uKHAsIGFzLmZhY3Rvcih0aGlzX3RyYWl0KSkKYXVjLm1vZGVsIDwtIHBlcmZvcm1hbmNlKHByLCBtZWFzdXJlID0gImF1YyIpQHkudmFsdWVzW1sxXV0KCmBgYAoKCgpgYGB7cn0KIyMgUGh5bG9nZW5ldGljIHNpZ25hbCAoRCkKUGh5bG9nZW5ldGljX3NpZ25hbCA8LSBEc2lnKG15dHJlZSA9IHRoaXNfdHJlZSwgbXlXb3JsZCA9IHRoaXNfd29ybGQpCgpgYGAKCgojIFNwYXRpYWwgTG9jYXRpb25zCgpgYGB7cn0KCiMjIFNwYXRpYWwgQW5hbHlzaXMKbmJzMCA8LSBrbmVhcm5laWdoKGFzLm1hdHJpeCh0aGlzX3dvcmxkWywgMjozXSksIGsgPSA3LCBsb25nbGF0ID0gVFJVRSkKbmJzIDwtIGtubjJuYihuYnMwLCBzeW0gPSBUUlVFKSAjIDcgc3ltbWV0cmljIG5laWdoYm9ycwpuYnMubGlzdHcgPC0gbmIybGlzdHcobmJzKQpmYWN0b3JzLm5icyA8LSBhcy5mYWN0b3IoaWZlbHNlKGlzLm5hKHRoaXNfd29ybGRbLCA2XSksIDMsIHRoaXNfd29ybGRbLCA2XSkpCnNwYXRpYWwudGVzdHMgPC0gam9pbmNvdW50LnRlc3QoZnggPSBmYWN0b3JzLm5icywgbGlzdHcgPSBuYnMubGlzdHcpCnNwYXRpYWwudGVzdHMuZm9yYSA8LSBzcGF0aWFsLnRlc3RzW1sxXV0kc3RhdGlzdGljCnNwYXRpYWwudGVzdHMuZG9tIDwtIHNwYXRpYWwudGVzdHNbWzJdXSRzdGF0aXN0aWMKI3ByZXZhbGVuY2UgPC0gKE4uZm9yLmRvbVsxXSAtIE4uZm9yLmRvbVsyXSkgLyBzdW0oTi5mb3IuZG9tKQpgYGAKCgpgYGB7cn0KcmVzdWx0c19zdW1tYXJ5X21hdHJpeF8xIDwtIGNiaW5kKAoKICAgICAgICBudW1iZXJfb2ZfYnJhbmNoZXMsCiAgICAgICAgI1B5bG9fZGl2ZXJzaXR5X2lzX3N1bV9vZl9CTCwKICAgICAgICAjYXZlcmFnZV9waHlsb2dlbmV0aWNfZGl2ZXJzaXR5X2lzX21lYW5fb2ZfQkwsCiAgICAgICAgI3ZhcmlhbmNlX1B5bG9fZGl2ZXJzaXR5X2lzX3ZhcmlhbmNlX29mX0JMLAoKICAgICAgICBGX3F1YWRyYXRpY19lbnRyb3B5X2lzX3N1bV9vZl9QRCwKICAgICAgICBNZWFuX3BhaXJ3aXNlX2Rpc3RhbmNlLAogICAgICAgIHZhcmlhbmNlX3BhaXJ3aXNlX2Rpc3RhbmNlLAoKICAgICAgICAjRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzc19zdW0sCiAgICAgICAgI21lYW5fUGh5bG9nZW5ldGljX2lzb2xhdGlvbiwKICAgICAgICAjdmFyaWFuY2VfUGh5bG9nZW5ldGljX2lzb2xhdGlvbiwKCiAgICAgICAgZ2FtbWEsCiAgICAgICAgZ2FtbWFfcF92YWx1ZSwKICAgICAgICBzcGVjaWF0aW9uX3JhdGUsCiAgICAgICAgZXh0aW5jdGlvbl9yYXRlLAogICAgICAgIGV4dGluY3Rpb25fcGVyX3NwZWNpYXRpb24sCiAgICAgICAgc3BlY2lhdGlvbl9taW51c19leHRpbmN0aW9uLAogICAgICAgIHRyYWl0XzFfc3BlY2lhdGlvbiwKICAgICAgICB0cmFpdF8yX3NwZWNpYXRpb24gLAogICAgICAgIHRyYWl0XzFfZXh0aW5jdGlvbiAsCiAgICAgICAgdHJhaXRfMl9leHRpbmN0aW9uICwKICAgICAgICB0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMV90b18yICwKICAgICAgICB0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMl90b18xICwKICAgICAgICB0cmFuc2l0aW9uX3JhdGVfcmF0aW9fMXRvMl9vdmVyXzJ0bzEgLAogICAgICAgIFBoeWxvZ2VuZXRpY19zaWduYWwsCiAgICAgICAgc3BhdGlhbC50ZXN0cy5mb3JhLAogICAgICAgIHNwYXRpYWwudGVzdHMuZG9tLAogICAgICAgIyBwcmV2YWxlbmNlLAogICAgICAgIyBhdWMubW9kZWwsCiAgICAgICAgZWZmZWN0LnNpemUKICAgICAgKQogICAgICAjcm93bmFtZXMocmVzdWx0c19zdW1tYXJ5X21hdHJpeF8xKSA8LSAxCgogICAgICAjcmVzdWx0c19zdW1tYXJ5X21hdHJpeF8yIDwtIGNiaW5kKAogICAgICAjICBjKEV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3MsTkEpLAogICAgICAjICBsaW5lYWdlc190aHJvdWdoX3RpbWUsCiAgICAgICMgIHRpbWVfc3RlcHMKICAgICAgIykKICAgICAgI2NvbG5hbWVzKHJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMikgPC0gYygiRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzcyIsICJsaW5lYWdlc190aHJvdWdoX3RpbWUiLCAidGltZV9zdGVwcyIpCiAgICAgICNoZWFkKHJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMikKCiAgICAgICMjIyBSZXR1cm5zIGZyb20gZnVuY3Rpb24gaW4gbGlzdCBmb3JtCiAgICAgICNyZXR1cm5zIDwtIGxpc3QoCiAgICAgICAgI0JyYW5jaF9MZW5ndGhzLAogICAgICAgICNQYWlyd2lzZV9kaXN0LAogICAgICAjICByZXN1bHRzX3N1bW1hcnlfbWF0cml4XzEsCiAgICAgICMgIHJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMgoKICAgICAgIykKCiAgICAgICNuYW1lcyhyZXR1cm5zKSA8LSBjKAogICAgICAgICMiQnJhbmNoX0xlbmd0aHMiLAogICAgICAgICMiUGFpcndpc2VfZGlzdGFuY2UiLAogICAgICAgIyAicmVzdWx0c19zdW1tYXJ5X29mX3NpbmdsZV92YWx1ZV9vdXRwdXRzIiwKICAgICAgICMgInJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfb2ZfbXVsdGlfdmFsdWVfb3V0cHV0cyIKICAgICAgIykKICAgICAgCiAgICAgIApgYGAKCgoKIyMgTW9kdWxlMigpIHJldHVybnMgdGhlc2UgdHdvIG1hdHJpY2VzIGFzIGEgbGlzdCAKCgoKYGBge3IsIGVjaG89RkFMU0V9CiNrYWJsZShyZXR1cm5zJHJlc3VsdHNfc3VtbWFyeV9vZl9zaW5nbGVfdmFsdWVfb3V0cHV0cywgY2FwdGlvbj0gIlRoaXMgaXMgb3VyIHdvcmxkIikKICAgICAKYGBgCgoKYGBge3IsIGVjaG89RkFMU0V9CiAja2FibGUocmV0dXJucyRyZXN1bHRzX3N1bW1hcnlfbWF0cml4X29mX211bHRpX3ZhbHVlX291dHB1dHMsIGNhcHRpb249ICJUaGlzIGlzIG91ciB3b3JsZCIpCmBgYAoKCiMgSGVyZSBpcyB0aGUgZXhhY3QgdmVyc2lvbiBpbiBSCmBgYHtyfQojIyBUaGlzIG1vZHVsZSBhbmFseXplcyB0aGUgcmVzdWx0cyBmcm9tIG1vZHVsZSAxIGFuZCByZXR1cm5zIGEgbGlzdCBiYXNlZCBvbiBob3cgbWFueSB2YWx1ZXMgZWFjaCBzdGF0IHJldHVybnMKIyMgVHkgVHVmZiBhbmQgQnJ1bm8gVmlsZWxhCiMjIDI0IEF1Z3VzdCAyMDE2CgojIyMjIyMgU3BlY2lmeSBmdW5jdGlvbiAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCk1vZHVsZV8yIDwtIGZ1bmN0aW9uKE1vZHVsZV8xX291dHB1dCkgewogIGNhdCgiXG5BbmFseXppbmc6IDAlIFsiKQogIGlmIChhbnkoaXMubmEoTW9kdWxlXzFfb3V0cHV0KSkpIHsKICAgIGNhdCgiLS0tLS0tLS0tLV0iKQogICAgcmV0dXJuKE5BKQogIH0gZWxzZSB7CgogICAgdGhpc190cmVlIDwtIE1vZHVsZV8xX291dHB1dCRteXRyZWUKICAgIHRoaXNfd29ybGQgPC0gTW9kdWxlXzFfb3V0cHV0JG15V29ybGQKCgogICAgIyMjIyMgKDApIFB1bGwgbmVjZXNzYXJ5IHZhcmlhYmxlcyBmcm9tIHNpbXVsYXRlZCB0cmVlcyBhbmQgb3JnYW5pemUgaW50byBhIHNpbmdsZSBvYmplY3QgZm9yIGFsbCB0aGUgdGVzdHMgYmVsb3cgdG8gcHVsbCBmcm9tLgoKICAgICNzdHIoYWxsX3RyZWVzKQogICAgI3N0cih0aGlzX3RyZWUpCgoKICAgICMjIDBhKSBCcmFuY2ggbGVuZ3RocwogICAgQnJhbmNoX0xlbmd0aHMgPC0gdGhpc190cmVlJGVkZ2UubGVuZ3RoCiAgICBudW1iZXJfb2ZfYnJhbmNoZXMgPC0gbGVuZ3RoKEJyYW5jaF9MZW5ndGhzKQoKICAgICMgQW5jaG9yIHRlc3QgPSBQRCAoRmFpdGgncyBwaHlsb2dlbmV0aWMgZGl2ZXJzaXR5KQogICAgUHlsb19kaXZlcnNpdHlfaXNfc3VtX29mX0JMIDwtIHN1bShCcmFuY2hfTGVuZ3RocykKCiAgICAjIGF2UEQgLS0gQXZlcmFnZSBwaHlsb2dlbmV0aWMgZGl2ZXJzaXR5CiAgICBhdmVyYWdlX3BoeWxvZ2VuZXRpY19kaXZlcnNpdHlfaXNfbWVhbl9vZl9CTCA8LSBtZWFuKEJyYW5jaF9MZW5ndGhzKQoKICAgIHZhcmlhbmNlX1B5bG9fZGl2ZXJzaXR5X2lzX3ZhcmlhbmNlX29mX0JMIDwtIHZhcihCcmFuY2hfTGVuZ3RocykKICAgIGNhdCgiLSIpCiAgICAjIyAwYikgUGFpcndpc2UgZGlzdGFuY2UgYmV0d2VlbiB0aXBzCiAgICBQYWlyd2lzZV9kaXN0IDwtIGNvcGhlbmV0aWMucGh5bG8odGhpc190cmVlKQogICAgY2F0KCItIikKICAgICMgMmIpIFBhaXJ3aXNlIGRpc3RhbmNlIC0tIFN1bSBvZiBwYWlyd2lzZSBkaXN0YW5jZXMKCiAgICAjIEYgLS0gRXh0ZW5zaXZlIHF1YWRyYXRpYyBlbnRyb3B5CiAgICBGX3F1YWRyYXRpY19lbnRyb3B5X2lzX3N1bV9vZl9QRCA8LSBzdW0oUGFpcndpc2VfZGlzdCkKCiAgICAjTWVhbiBpbnRlci1zcGVjaWVzIGRpc3RhbmNlcwoKICAgICMgQW5jaG9yIHRlc3QgPSBNUEQgKG1lYW4gcGFpcndpc2UgZGlzdGFuY2UpCgogICAgTWVhbl9wYWlyd2lzZV9kaXN0YW5jZSA8LSBtZWFuKFBhaXJ3aXNlX2Rpc3QpCgogICAgY2F0KCItIikKICAgICNQYWlyd2lzZSBkaXN0YW5jZS9hbGwgZGlzdGFuY2VzIC0tIFZhcmlhbmNlIG9mIHBhaXJ3aXNlIGRpc3RhbmNlcwoKICAgICMgQW5jaG9yIHRlc3QgPSBWUEQgKHZhcmlhdGlvbiBvZiBwYWlyd2lzZSBkaXN0YW5jZSkKCiAgICB2YXJpYW5jZV9wYWlyd2lzZV9kaXN0YW5jZSA8LSB2YXIoYXMudmVjdG9yKFBhaXJ3aXNlX2Rpc3QpKQoKCgoKICAgICMjIDBjKSBQaHlsb2dlbmV0aWMgaXNvbGF0aW9uCgogICAgIyBVc2luZyBlcXVhbC5zcGxpdHMgbWV0aG9kLCBmYXN0ZXIgY29tcHV0YXRpb24KICAgIEV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3MgPC0gZXZvbC5kaXN0aW5jdDIodGhpc190cmVlLCB0eXBlID0gImZhaXIucHJvcG9ydGlvbiIpCiAgICBjYXQoIi0iKQogICAgIyBFRCAtIFN1bW1lZCBldm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzCgogICAgRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzc19zdW0gPC0gc3VtKEV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3MpCgogICAgIyMgM2QpIFBoeWxvZ2VuZXRpYyBpc29sYXRpb24gLS0gTWVhbiBvZiBzcGVjaWVzIGV2b2x1dGlvbmFyeSBkaXN0aW5jdGl2ZW5lc3MKCiAgICAjIG1lYW4oRUQpCgogICAgbWVhbl9QaHlsb2dlbmV0aWNfaXNvbGF0aW9uIDwtIG1lYW4oRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzcykKCiAgICAjIyA0ZCkgUGh5bG9nZW5ldGljIGlzb2xhdGlvbiAtLSBWYXJpYW5jZSBvZiBzcGVjaWVzIGlzb2xhdGlvbiBtZXRyaWNzCgogICAgI3ZhcihFRCkKCiAgICB2YXJpYW5jZV9QaHlsb2dlbmV0aWNfaXNvbGF0aW9uIDwtIHZhcihFdm9sdXRpb25hcnlfZGlzdGluY3RpdmVuZXNzKQogICAgY2F0KCItIikKCiAgICAjIyBUcmVlIHRvcG9sb2d5CgogICAgI0dhbW1hIGluZGV4CgogICAgbHR0cyA8LSBsdHQodGhpc190cmVlLCBnYW1tYSA9IFRSVUUsIHBsb3QgPSBGQUxTRSkKICAgIGxpbmVhZ2VzX3Rocm91Z2hfdGltZSA8LSBhcy5udW1lcmljKGx0dHNbWzFdXSkKICAgIHRpbWVfc3RlcHMgPC0gYXMubnVtZXJpYyhsdHRzW1syXV0pCiAgICBnYW1tYSA8LSBsdHRzW1szXV0KICAgIGdhbW1hX3BfdmFsdWUgPC0gbHR0c1tbNF1dCiAgICBjYXQoIi0iKQoKICAgIGNvbGxlc3Nfc3RhdCA8LSBjb2xsZXNzKGFzLnRyZWVzaGFwZSh0aGlzX3RyZWUpKQogICAgc2Fja2luX2luZGV4IDwtIHNhY2tpbihhcy50cmVlc2hhcGUodGhpc190cmVlKSkKICAgIHRyZWVfc2hhcGVfc3RhdCA8LSBzaGFwZS5zdGF0aXN0aWMoYXMudHJlZXNoYXBlKHRoaXNfdHJlZSkpCgogICAgIyMjIyMgKDUpIFRyZWUgbWV0cmljIC0tIE1hY3JvZXZvbHV0aW9uYXJ5IC0gUmF0ZSBhbmQgcmF0ZSBjaGFuZ2VzICMjIyMjIyMjIyMjIyMjIwogICAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiAgICAjIyBTcGVjaWF0aW9uIHZzIGV4dGluY3Rpb24gcmF0ZXMgYW5kIE5ldCBkaXZlcnNpZmljYXRpb24KICAgIGJkcyA8LSBiZCh0aGlzX3RyZWUpCiAgICBzcGVjaWF0aW9uX3JhdGUgPC0gYmRzWzFdCiAgICBleHRpbmN0aW9uX3JhdGUgPC0gYmRzWzJdCiAgICBleHRpbmN0aW9uX3Blcl9zcGVjaWF0aW9uIDwtIGJkc1szXQogICAgc3BlY2lhdGlvbl9taW51c19leHRpbmN0aW9uIDwtIGJkc1s0XQogICAgY2F0KCItIikKCgogICAgIyMgU3BlY2lhdGlvbiB2cyBleHRpbmN0aW9uIHJhdGVzIGFuZCBOZXQgZGl2ZXJzaWZpY2F0aW9uIGRlcGVuZGVudCBvbiB0cmFpdAogICAgTi5mb3IuZG9tIDwtIHRhYmxlKHRoaXNfd29ybGRbLCA2XSkKICAgIGlmKGxlbmd0aChOLmZvci5kb20pID09IDIpIHsKICAgICAgcGFyLmRpdi5kZXAgPC0gRGl2RGVwKCBteXRyZWUgPSB0aGlzX3RyZWUsIG15V29ybGQgPSB0aGlzX3dvcmxkKQogICAgICB0cmFpdF8xX3NwZWNpYXRpb24gPC0gcGFyLmRpdi5kZXBbMV0KICAgICAgdHJhaXRfMl9zcGVjaWF0aW9uIDwtIHBhci5kaXYuZGVwWzJdCiAgICAgIHRyYWl0XzFfZXh0aW5jdGlvbiA8LSBwYXIuZGl2LmRlcFszXQogICAgICB0cmFpdF8yX2V4dGluY3Rpb24gPC0gcGFyLmRpdi5kZXBbNF0KICAgICAgdHJhbnNpdGlvbl9mcm9tX3RyYWl0XzFfdG9fMiA8LSBwYXIuZGl2LmRlcFs1XQogICAgICB0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMl90b18xIDwtIHBhci5kaXYuZGVwWzZdCiAgICAgIHRyYW5zaXRpb25fcmF0ZV9yYXRpb18xdG8yX292ZXJfMnRvMSA8LSB0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMV90b18yL3RyYW5zaXRpb25fZnJvbV90cmFpdF8yX3RvXzEKICAgICAgY2F0KCItIikKCiAgICAgICMjIFBoeWxvZ2VuZXRpYyBzaWduYWwgKEQpCiAgICAgIFBoeWxvZ2VuZXRpY19zaWduYWwgPC0gRHNpZyhteXRyZWUgPSB0aGlzX3RyZWUsIG15V29ybGQgPSB0aGlzX3dvcmxkKQogICAgICBjYXQoIi0iKQoKICAgICAgIyMgU3BhdGlhbCBBbmFseXNpcwogICAgICBuYnMwIDwtIGtuZWFybmVpZ2goYXMubWF0cml4KHRoaXNfd29ybGRbLCAyOjNdKSwgayA9IDcsIGxvbmdsYXQgPSBUUlVFKQogICAgICBuYnMgPC0ga25uMm5iKG5iczAsIHN5bSA9IFRSVUUpICMgNyBzeW1tZXRyaWMgbmVpZ2hib3JzCiAgICAgIG5icy5saXN0dyA8LSBuYjJsaXN0dyhuYnMpCiAgICAgIGZhY3RvcnMubmJzIDwtIGFzLmZhY3RvcihpZmVsc2UoaXMubmEodGhpc193b3JsZFssIDZdKSwgMywgdGhpc193b3JsZFssIDZdKSkKICAgICAgc3BhdGlhbC50ZXN0cyA8LSBqb2luY291bnQudGVzdChmeCA9IGZhY3RvcnMubmJzLCBsaXN0dyA9IG5icy5saXN0dykKICAgICAgc3BhdGlhbC50ZXN0cy5mb3JhIDwtIHNwYXRpYWwudGVzdHNbWzFdXSRzdGF0aXN0aWMKICAgICAgc3BhdGlhbC50ZXN0cy5kb20gPC0gc3BhdGlhbC50ZXN0c1tbMl1dJHN0YXRpc3RpYwogICAgICBwcmV2YWxlbmNlIDwtIChOLmZvci5kb21bMV0gLSBOLmZvci5kb21bMl0pIC8gc3VtKE4uZm9yLmRvbSkKICAgICAgY2F0KCItIikKICAgIH0gZWxzZSB7CiAgICAgIHRyYWl0XzFfc3BlY2lhdGlvbiA8LSBOQQogICAgICB0cmFpdF8yX3NwZWNpYXRpb24gPC0gTkEKICAgICAgdHJhaXRfMV9leHRpbmN0aW9uIDwtIE5BCiAgICAgIHRyYWl0XzJfZXh0aW5jdGlvbiA8LSBOQQogICAgICB0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMV90b18yIDwtIE5BCiAgICAgIHRyYW5zaXRpb25fZnJvbV90cmFpdF8yX3RvXzEgPC0gTkEKICAgICAgdHJhbnNpdGlvbl9yYXRlX3JhdGlvXzF0bzJfb3Zlcl8ydG8xIDwtIE5BCiAgICAgIFBoeWxvZ2VuZXRpY19zaWduYWwgPC0gTkEKICAgICAgc3BhdGlhbC50ZXN0cy5mb3JhIDwtIE5BCiAgICAgIHNwYXRpYWwudGVzdHMuZG9tIDwtIE5BCiAgICAgIHByZXZhbGVuY2UgPC0gaWZlbHNlKG5hbWVzKHRhYmxlKHRoaXNfd29ybGRbLCA2XSlbMV0pID09ICIxIiwgMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgLTEpCiAgICAgIGNhdCgiLS0tIikKCiAgICB9CgoKCgogICAgcmVzdWx0c19zdW1tYXJ5X21hdHJpeF8xIDwtIGNiaW5kKAoKICAgICAgbnVtYmVyX29mX2JyYW5jaGVzLAogICAgICBQeWxvX2RpdmVyc2l0eV9pc19zdW1fb2ZfQkwsCiAgICAgIGF2ZXJhZ2VfcGh5bG9nZW5ldGljX2RpdmVyc2l0eV9pc19tZWFuX29mX0JMLAogICAgICB2YXJpYW5jZV9QeWxvX2RpdmVyc2l0eV9pc192YXJpYW5jZV9vZl9CTCwKCiAgICAgIEZfcXVhZHJhdGljX2VudHJvcHlfaXNfc3VtX29mX1BELAogICAgICBNZWFuX3BhaXJ3aXNlX2Rpc3RhbmNlLAogICAgICB2YXJpYW5jZV9wYWlyd2lzZV9kaXN0YW5jZSwKCiAgICAgIGNvbGxlc3Nfc3RhdCAsCiAgICAgIHNhY2tpbl9pbmRleCAsCiAgICAgIHRyZWVfc2hhcGVfc3RhdCwKCiAgICAgIEV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3Nfc3VtLAogICAgICBtZWFuX1BoeWxvZ2VuZXRpY19pc29sYXRpb24sCiAgICAgIHZhcmlhbmNlX1BoeWxvZ2VuZXRpY19pc29sYXRpb24sCgogICAgICBnYW1tYSwKICAgICAgZ2FtbWFfcF92YWx1ZSwKICAgICAgc3BlY2lhdGlvbl9yYXRlLAogICAgICBleHRpbmN0aW9uX3JhdGUsCiAgICAgIGV4dGluY3Rpb25fcGVyX3NwZWNpYXRpb24sCiAgICAgIHNwZWNpYXRpb25fbWludXNfZXh0aW5jdGlvbiwKICAgICAgdHJhaXRfMV9zcGVjaWF0aW9uLAogICAgICB0cmFpdF8yX3NwZWNpYXRpb24gLAogICAgICB0cmFpdF8xX2V4dGluY3Rpb24gLAogICAgICB0cmFpdF8yX2V4dGluY3Rpb24gLAogICAgICB0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMV90b18yICwKICAgICAgdHJhbnNpdGlvbl9mcm9tX3RyYWl0XzJfdG9fMSAsCiAgICAgIHRyYW5zaXRpb25fcmF0ZV9yYXRpb18xdG8yX292ZXJfMnRvMSAsCiAgICAgIFBoeWxvZ2VuZXRpY19zaWduYWwsCiAgICAgIHNwYXRpYWwudGVzdHMuZm9yYSwKICAgICAgc3BhdGlhbC50ZXN0cy5kb20sCiAgICAgIHByZXZhbGVuY2UKICAgICkKICAgIHJvd25hbWVzKHJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMSkgPC0gMQoKICAgIHJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMiA8LSBjYmluZCgKICAgICAgYyhFdm9sdXRpb25hcnlfZGlzdGluY3RpdmVuZXNzLE5BKSwKICAgICAgbGluZWFnZXNfdGhyb3VnaF90aW1lLAogICAgICB0aW1lX3N0ZXBzCiAgICApCiAgICBjb2xuYW1lcyhyZXN1bHRzX3N1bW1hcnlfbWF0cml4XzIpIDwtIGMoIkV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJsaW5lYWdlc190aHJvdWdoX3RpbWUiLCAidGltZV9zdGVwcyIpCiAgICBoZWFkKHJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMikKCiAgICAjIyMgUmV0dXJucyBmcm9tIGZ1bmN0aW9uIGluIGxpc3QgZm9ybQogICAgcmV0dXJucyA8LSBsaXN0KAogICAgICAjQnJhbmNoX0xlbmd0aHMsCiAgICAgICNQYWlyd2lzZV9kaXN0LAogICAgICByZXN1bHRzX3N1bW1hcnlfbWF0cml4XzEsCiAgICAgIHJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMgoKICAgICkKCiAgICBuYW1lcyhyZXR1cm5zKSA8LSBjKAogICAgICAjIkJyYW5jaF9MZW5ndGhzIiwKICAgICAgIyJQYWlyd2lzZV9kaXN0YW5jZSIsCiAgICAgICJyZXN1bHRzX3N1bW1hcnlfb2Zfc2luZ2xlX3ZhbHVlX291dHB1dHMiLAogICAgICAicmVzdWx0c19zdW1tYXJ5X21hdHJpeF9vZl9tdWx0aV92YWx1ZV9vdXRwdXRzIgogICAgKQogICAgY2F0KCJdIDEwMCUiKQoKICAgIHJldHVybihyZXR1cm5zKQoKICB9Cn0KCgojTW9kdWxlXzIobXlPdXQpCgpgYGAKCgojIyBSZWZlcmVuY2VzCgoKCjwhLS1jaGFwdGVyOmVuZDpNb2R1bGVfMl9tYXJrZG93bi5SbWQtLT4KCi0tLQp0aXRsZTogIkQtcGxhY2UgRkFSTSBkb2N1bWVudGF0aW9uOiBNb2R1bGUgMyB0aHJvdWdoIHRpbWUiCmF1dGhvcjogIlR5IFR1ZmYsIEJydW5vIFZpbGVsYSwgYW5kIENhcmxvcyBCb3Rlcm8iCmRhdGU6ICdwcm9qZWN0IGJlZ2FuOiAxNSBNYXkgMjAxNiwgZG9jdW1lbnQgdXBkYXRlZDogYHIgc3RyZnRpbWUoU3lzLnRpbWUoKSwgZm9ybWF0CiAgPSAiJWQgJUIgJVkiKWAnCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKYmlibGlvZ3JhcGh5OiBGQVJNIHBhY2thZ2UuYmliCi0tLQoKCmBgYHtyfQpzZXR3ZCgifi9Cb3ggU3luYy9jb2xsaWRpbmcgcmFuZ2VzL1NpbXVsYXRpb25zX2h1bWFucy9SZXN1bHRzL1JGX2RhaWx5X291dHB1dCIpCgpkZXRhaWxzIDwtIGZpbGUuaW5mbyhsaXN0LmZpbGVzKCkpCgp0cmltbWVkX2RldGFpbHMgPC0gZGV0YWlsc1t3aGljaChsaXN0LmZpbGVzKCkgPT0gbGlzdC5maWxlcyhwYXR0ZXJuID0gIkZvdXJfbW9kZWxfY29tcGFyZV9yZXN1bHRzX2V4dGluY3QqIikpLF0Kb3JkIDwtIG9yZGVyKHRyaW1tZWRfZGV0YWlscyRtdGltZSwgZGVjcmVhc2luZyA9IFRSVUUpCnJvd25hbWVzKHRyaW1tZWRfZGV0YWlsc1tvcmQsXSlbMV0KbG9hZChyb3duYW1lcyh0cmltbWVkX2RldGFpbHNbb3JkLF0pWzFdKQpleHRpbmN0IDwtIENvbmNhdGVuYXRlZF9kYXRhCgoKCgpgYGAKCgpgYGB7cn0Kc3RyKGZpdCkKYGBgCgoKYGBge3J9CmZpdCRjb25mdXNpb24KYXMudmVjdG9yKGZpdCRjb25mdXNpb24pCmFzLnZlY3RvcihmaXQkdGVzdCRjb25mdXNpb24pCgpgYGAKCgpgYGB7cn0KZml0JGltcG9ydGFuY2VbLDVdCmZpdCRpbXBvcnRhbmNlU0RbLDVdCmBgYAoKCgpgYGB7cn0KCgpzdHIoZml0KQpmaXQkY29uZnVzaW9uCnBsb3QoZml0JGVyci5yYXRlWywxXSkKbGluZXMoZml0JGVyci5yYXRlWywyXSkKbGluZXMoZml0JGVyci5yYXRlWywzXSkKbGluZXMoZml0JGVyci5yYXRlWyw0XSkKbGluZXMoZml0JGVyci5yYXRlWyw1XSkKCgpgYGAKCjwhLS1jaGFwdGVyOmVuZDpNb2R1bGVfM19hY3Jvc3Nfc3Vic2V0dGVkX3NhbXBsZV9zaXplcy5SbWQtLT4KCi0tLQp0aXRsZTogIkQtcGxhY2UgRkFSTSBkb2N1bWVudGF0aW9uOiBNb2R1bGUgMyIKYXV0aG9yOiAiVHkgVHVmZiwgQnJ1bm8gVmlsZWxhLCBhbmQgQ2FybG9zIEJvdGVybyIKZGF0ZTogJ3Byb2plY3QgYmVnYW46IDE1IE1heSAyMDE2LCBkb2N1bWVudCB1cGRhdGVkOiBgciBzdHJmdGltZShTeXMudGltZSgpLCBmb3JtYXQKICA9ICIlZCAlQiAlWSIpYCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgd29yZF9kb2N1bWVudDogZGVmYXVsdApiaWJsaW9ncmFwaHk6IEZBUk0gcGFja2FnZS5iaWIKLS0tCmBgYHtyfQpsaWJyYXJ5KHBuZykKYGBgCgoKCmBgYHtyfQojIyBGaXJzdCBjb25zb2xpZGF0ZSB0aGUgYXZhaWxhYmxlIGZpbGVzIGludG8gYSBzaW5nbGUgdGFibGUKICAgIAogICAgICBwYXRoIDwtICJ+L0JveCBTeW5jL0ZvdXIgbW9kZWwgY29tcGFyZS9Nb2R1bGUgMiIKICAgICAgICAgICAKICAgICAKICAgICAgICAgICBzZXR3ZChwYXRoKQogICAgbXlmaWxlc19mdWxsIDwtIGxpc3QuZGlycygpCiAgICBhbmFseXplX3RoaXNfbWFueSA8LSBsZW5ndGgobXlmaWxlc19mdWxsKQogICAgCiAgICBhdmFpbGFibGVfZmlsZXMgPC0gbWF0cml4KE5BLCAxLCAxKQogICAgCiAgICAgICAgCiAgICBmb3IoaSBpbiAxOiBhbmFseXplX3RoaXNfbWFueSl7CiAgICBhdmFpbGFibGVfZmlsZXMgPC0gcmJpbmQoYXZhaWxhYmxlX2ZpbGVzICwgYXMubWF0cml4KGxpc3QuZmlsZXMobXlmaWxlc19mdWxsW2ldLCBmdWxsLm5hbWVzID0gVFJVRSkpKQogICAgfQogICAgZGltKGF2YWlsYWJsZV9maWxlcykKICAgIAogICAgc3BsaXQuZmlsZS5uYW1lIDwtIHN0cnNwbGl0KGF2YWlsYWJsZV9maWxlc1sxMF0sIHNwbGl0ID0gIl8iKSAKICAgIAogICAgCiAgICAKIAphdmFpbGFibGUgPC0gbGlzdC5maWxlcygpCmZpbGVzIDwtIG1hdHJpeChyZXAoTkEsIDYyKSwgbGVuZ3RoKGF2YWlsYWJsZSksIDYyKQpkaW0oZmlsZXMpCmkgPC0gMTAKCgpmb3IoaSBpbiAxOmxlbmd0aChhdmFpbGFibGUpKXsKbG9hZChhdmFpbGFibGVbaV0pCm5hbWUgPC0gdW5saXN0KHN0cnNwbGl0KGF2YWlsYWJsZVtpXSwgc3BsaXQ9Il8iKSkKZmlsZXNbaSxdIDwtIGMoYXMudmVjdG9yKG1hdHJpeChuYW1lLCAxLDM1KSksbWF0cml4KFNpbV9zdGF0aXN0aWNzW1sxXV0sIDEsIDI3KSkKCn0KCgpjb2xuYW1lcyhmaWxlcykgPC0gIGMoCgoJTkEsCgkiYmFja2dyb3VuZF90YWtlb3Zlcl90eXBlIiAsCglOQSwKCSJyZXBsaWNhdGUiLAoJTkEsCgkiTW9kZWxfdHlwZSIsCglyZXAoTkEsMiksCgkic3BlY2lhdGlvbl9vZl9FbnZfTm9uRCIsCgkic3BlY2lhdGlvbl9vZl9FbnZfRCIsCgkic3BlY2lhdGlvbl9vZl9Gb3IiLAoJInNwZWNpYXRpb25fb2ZfRG9tIiwKCU5BLAoJImV4dGluY3Rpb25fb2ZfRW52X05vbkQiLAoJImV4dGluY3Rpb25fb2ZfRW52X0QiLAoJImV4dGluY3Rpb25fb2ZfRm9yIiwKCSJleHRpbmN0aW9uX29mX0RvbSIsCglOQSwKCSJQLmRpZmZ1c2lvbl9UYXJnZXRfZm9yYWdlciIsCgkiUC5kaWZmdXNpb25fVGFyZ2V0X2RvbWVzdGljYXRvciIsCgkiUC5kaWZmdXNpb25fU291cmNlX2ZvcmFnZXIiLAoJIlAuZGlmZnVzaW9uX1NvdXJjZV9kb21lc3RpY2F0b3IiLAoJTkEsCgkiUC50YWtlb3Zlcl9UYXJnZXRfZm9yYWdlciIsCgkiUC50YWtlb3Zlcl9UYXJnZXRfZG9tZXN0aWNhdG9yIiwKCSJQLnRha2VvdmVyX1NvdXJjZV9mb3JhZ2VyIiwKCSJQLnRha2VvdmVyX1NvdXJjZV9kb21lc3RpY2F0b3IiLAoJTkEsCgkiYXJpc2FsX29mX0Vudl9Ob25EIiwKCSJhcmlzYWxfb2ZfRW52X0QiLAoJImFyaXNhbF9vZl9Gb3IiLAoJImFyaXNhbF9vZl9Eb20iLAoJCglOQSwgCgkidGltZXN0ZXBzIiwgCglOQSwKICAgICAgICAKICAgICJudW1iZXJfb2ZfYnJhbmNoZXMiLAoJIlB5bG9fZGl2ZXJzaXR5X2lzX3N1bV9vZl9CTCIsCgkiYXZlcmFnZV9waHlsb2dlbmV0aWNfZGl2ZXJzaXR5X2lzX21lYW5fb2ZfQkwiLAoJInZhcmlhbmNlX1B5bG9fZGl2ZXJzaXR5X2lzX3ZhcmlhbmNlX29mX0JMIiwKCgkiRl9xdWFkcmF0aWNfZW50cm9weV9pc19zdW1fb2ZfUEQiLAoJIk1lYW5fcGFpcndpc2VfZGlzdGFuY2UiLAoJInZhcmlhbmNlX3BhaXJ3aXNlX2Rpc3RhbmNlIiwKCgkiRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzc19zdW0iLAoJIm1lYW5fUGh5bG9nZW5ldGljX2lzb2xhdGlvbiIsCgkidmFyaWFuY2VfUGh5bG9nZW5ldGljX2lzb2xhdGlvbiIsCgoJImdhbW1hIiwKCSJnYW1tYV9wX3ZhbHVlIiwKCSJzcGVjaWF0aW9uX3JhdGUiLAoJImV4dGluY3Rpb25fcmF0ZSIsCgkiZXh0aW5jdGlvbl9wZXJfc3BlY2lhdGlvbiIsCgkic3BlY2lhdGlvbl9taW51c19leHRpbmN0aW9uIiwKCSJ0cmFpdF8xX3NwZWNpYXRpb24iLAogIAkidHJhaXRfMl9zcGVjaWF0aW9uIiAsCiAgCSJ0cmFpdF8xX2V4dGluY3Rpb24iICwKICAJInRyYWl0XzJfZXh0aW5jdGlvbiIgLAogIAkidHJhbnNpdGlvbl9mcm9tX3RyYWl0XzFfdG9fMiIgLAogIAkidHJhbnNpdGlvbl9mcm9tX3RyYWl0XzJfdG9fMSIgLAogIAkidHJhbnNpdGlvbl9yYXRlX3JhdGlvXzF0bzJfb3Zlcl8ydG8xIiAsCiAgCSJQaHlsb2dlbmV0aWNfc2lnbmFsIiwKICAJInNwYXRpYWwudGVzdHMuZm9yYSIsCiAgCSJzcGF0aWFsLnRlc3RzLmRvbSIsCiAgCSJwcmV2YWxlbmNlIgogIAkKICAgIAogICkKCnJlc3VsdHNfdGFibGUgPC0gYXMuZGF0YS5mcmFtZShmaWxlcykKaGVhZChyZXN1bHRzX3RhYmxlKQpkaW0ocmVzdWx0c190YWJsZSkKQ29uY2F0ZW5hdGVkX2RhdGEgPC0gcmVzdWx0c190YWJsZQpzYXZlKENvbmNhdGVuYXRlZF9kYXRhLCBmaWxlPSJ+L0Rlc2t0b3AvRm91cl9tb2RlbF9jb21wYXJlX3Jlc3VsdHMuUmRhdGEiKQoKb25lIDwtIHN1YnNldChyZXN1bHRzX3RhYmxlLCBNb2RlbF90eXBlPT0iMDEiICkKdHdvIDwtIHN1YnNldChyZXN1bHRzX3RhYmxlLCBNb2RlbF90eXBlPT0iMDIiICkKdGhyZWUgPC0gc3Vic2V0KHJlc3VsdHNfdGFibGUsIE1vZGVsX3R5cGU9PSIwMyIgKQpmb3VyIDwtIHN1YnNldChyZXN1bHRzX3RhYmxlLCBNb2RlbF90eXBlPT0iMDQiICkKY3JvcCA8LSBtaW4obGVuZ3RoKG9uZVssMV0pLApsZW5ndGgodHdvWywxXSksCmxlbmd0aCh0aHJlZVssMV0pLApsZW5ndGgoZm91clssMV0pKQpvbmUgPC0gb25lWzE6Y3JvcCxdCnR3byA8LSB0d29bMTpjcm9wLF0KdGhyZWUgPC0gdGhyZWVbMTpjcm9wLF0KZm91ciA8LSBmb3VyWzE6Y3JvcCxdCgpDb25jYXRlbmF0ZWRfZGF0YSA8LSByYmluZChvbmUsIHR3bywgdGhyZWUsIGZvdXIpCmRpbShDb25jYXRlbmF0ZWRfZGF0YSkKCgoKCgpzYXZlKENvbmNhdGVuYXRlZF9kYXRhLCBmaWxlPXBhc3RlMCgifi9Cb3ggU3luYy9jb2xsaWRpbmcgcmFuZ2VzL1NpbXVsYXRpb25zX2h1bWFucy9SZXN1bHRzL2F2YWlsYWJsZSBkYWlseSBzdW1tYXJpZXMvRm91cl9tb2RlbF9jb21wYXJlX3Jlc3VsdHMiLCBmb3JtYXQoU3lzLnRpbWUoKSwgZm9ybWF0PSIlZF8lYl8lWSIpLCJfY3JvcF90b18iLCBjcm9wLCIuUmRhdGEiKSkKY3JvcAoKYGBgCgoKCgpgYGB7cn0KIyMgRmlyc3QgY29uc29saWRhdGUgdGhlIGF2YWlsYWJsZSBmaWxlcyBpbnRvIGEgc2luZ2xlIHRhYmxlCiAgICAKICAgICAgcGF0aCA8LSAifi9Cb3ggU3luYy9Gb3VyIG1vZGVsIGNvbXBhcmUvTW9kdWxlIDIgZXh0aW5jdCIKICAgICAgICAgICAKICAgICAKICAgICAgICAgICBzZXR3ZChwYXRoKQogICAgbXlmaWxlc19mdWxsIDwtIGxpc3QuZGlycygpCiAgICBhbmFseXplX3RoaXNfbWFueSA8LSBsZW5ndGgobXlmaWxlc19mdWxsKQogICAgCiAgICBhdmFpbGFibGVfZmlsZXMgPC0gbWF0cml4KE5BLCAxLCAxKQogICAgCiAgICAgICAgCiAgICBmb3IoaSBpbiAxOiBhbmFseXplX3RoaXNfbWFueSl7CiAgICBhdmFpbGFibGVfZmlsZXMgPC0gcmJpbmQoYXZhaWxhYmxlX2ZpbGVzICwgYXMubWF0cml4KGxpc3QuZmlsZXMobXlmaWxlc19mdWxsW2ldLCBmdWxsLm5hbWVzID0gVFJVRSkpKQogICAgfQogICAgZGltKGF2YWlsYWJsZV9maWxlcykKICAgIAogICAgc3BsaXQuZmlsZS5uYW1lIDwtIHN0cnNwbGl0KGF2YWlsYWJsZV9maWxlc1sxMF0sIHNwbGl0ID0gIl8iKSAKICAgIAogICAgCiAgICAKIAphdmFpbGFibGUgPC0gbGlzdC5maWxlcygpCmZpbGVzIDwtIG1hdHJpeChyZXAoTkEsIDYyKSwgbGVuZ3RoKGF2YWlsYWJsZSksIDYyKQpkaW0oZmlsZXMpCmkgPC0gMTAKCgpmb3IoaSBpbiAxOmxlbmd0aChhdmFpbGFibGUpKXsKbG9hZChhdmFpbGFibGVbaV0pCm5hbWUgPC0gdW5saXN0KHN0cnNwbGl0KGF2YWlsYWJsZVtpXSwgc3BsaXQ9Il8iKSkKZmlsZXNbaSxdIDwtIGMoYXMudmVjdG9yKG1hdHJpeChuYW1lLCAxLDM1KSksbWF0cml4KFNpbV9zdGF0aXN0aWNzW1sxXV0sIDEsIDI3KSkKCn0KCgpjb2xuYW1lcyhmaWxlcykgPC0gIGMoCgoJTkEsCgkiYmFja2dyb3VuZF90YWtlb3Zlcl90eXBlIiAsCglOQSwKCSJyZXBsaWNhdGUiLAoJTkEsCgkiTW9kZWxfdHlwZSIsCglyZXAoTkEsMiksCgkic3BlY2lhdGlvbl9vZl9FbnZfTm9uRCIsCgkic3BlY2lhdGlvbl9vZl9FbnZfRCIsCgkic3BlY2lhdGlvbl9vZl9Gb3IiLAoJInNwZWNpYXRpb25fb2ZfRG9tIiwKCU5BLAoJImV4dGluY3Rpb25fb2ZfRW52X05vbkQiLAoJImV4dGluY3Rpb25fb2ZfRW52X0QiLAoJImV4dGluY3Rpb25fb2ZfRm9yIiwKCSJleHRpbmN0aW9uX29mX0RvbSIsCglOQSwKCSJQLmRpZmZ1c2lvbl9UYXJnZXRfZm9yYWdlciIsCgkiUC5kaWZmdXNpb25fVGFyZ2V0X2RvbWVzdGljYXRvciIsCgkiUC5kaWZmdXNpb25fU291cmNlX2ZvcmFnZXIiLAoJIlAuZGlmZnVzaW9uX1NvdXJjZV9kb21lc3RpY2F0b3IiLAoJTkEsCgkiUC50YWtlb3Zlcl9UYXJnZXRfZm9yYWdlciIsCgkiUC50YWtlb3Zlcl9UYXJnZXRfZG9tZXN0aWNhdG9yIiwKCSJQLnRha2VvdmVyX1NvdXJjZV9mb3JhZ2VyIiwKCSJQLnRha2VvdmVyX1NvdXJjZV9kb21lc3RpY2F0b3IiLAoJTkEsCgkiYXJpc2FsX29mX0Vudl9Ob25EIiwKCSJhcmlzYWxfb2ZfRW52X0QiLAoJImFyaXNhbF9vZl9Gb3IiLAoJImFyaXNhbF9vZl9Eb20iLAoJCglOQSwgCgkidGltZXN0ZXBzIiwgCglOQSwKICAgICAgICAKICAgICJudW1iZXJfb2ZfYnJhbmNoZXMiLAoJIlB5bG9fZGl2ZXJzaXR5X2lzX3N1bV9vZl9CTCIsCgkiYXZlcmFnZV9waHlsb2dlbmV0aWNfZGl2ZXJzaXR5X2lzX21lYW5fb2ZfQkwiLAoJInZhcmlhbmNlX1B5bG9fZGl2ZXJzaXR5X2lzX3ZhcmlhbmNlX29mX0JMIiwKCgkiRl9xdWFkcmF0aWNfZW50cm9weV9pc19zdW1fb2ZfUEQiLAoJIk1lYW5fcGFpcndpc2VfZGlzdGFuY2UiLAoJInZhcmlhbmNlX3BhaXJ3aXNlX2Rpc3RhbmNlIiwKCgkiRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzc19zdW0iLAoJIm1lYW5fUGh5bG9nZW5ldGljX2lzb2xhdGlvbiIsCgkidmFyaWFuY2VfUGh5bG9nZW5ldGljX2lzb2xhdGlvbiIsCgoJImdhbW1hIiwKCSJnYW1tYV9wX3ZhbHVlIiwKCSJzcGVjaWF0aW9uX3JhdGUiLAoJImV4dGluY3Rpb25fcmF0ZSIsCgkiZXh0aW5jdGlvbl9wZXJfc3BlY2lhdGlvbiIsCgkic3BlY2lhdGlvbl9taW51c19leHRpbmN0aW9uIiwKCSJ0cmFpdF8xX3NwZWNpYXRpb24iLAogIAkidHJhaXRfMl9zcGVjaWF0aW9uIiAsCiAgCSJ0cmFpdF8xX2V4dGluY3Rpb24iICwKICAJInRyYWl0XzJfZXh0aW5jdGlvbiIgLAogIAkidHJhbnNpdGlvbl9mcm9tX3RyYWl0XzFfdG9fMiIgLAogIAkidHJhbnNpdGlvbl9mcm9tX3RyYWl0XzJfdG9fMSIgLAogIAkidHJhbnNpdGlvbl9yYXRlX3JhdGlvXzF0bzJfb3Zlcl8ydG8xIiAsCiAgCSJQaHlsb2dlbmV0aWNfc2lnbmFsIiwKICAJInNwYXRpYWwudGVzdHMuZm9yYSIsCiAgCSJzcGF0aWFsLnRlc3RzLmRvbSIsCiAgCSJwcmV2YWxlbmNlIgogIAkKICAgIAogICkKCkNvbmNhdGVuYXRlZF9kYXRhIDwtIGFzLmRhdGEuZnJhbWUoZmlsZXMpCmhlYWQoQ29uY2F0ZW5hdGVkX2RhdGEpCmRpbShDb25jYXRlbmF0ZWRfZGF0YSkKCnNhdmUoQ29uY2F0ZW5hdGVkX2RhdGEsIGZpbGU9cGFzdGUwKCJ+L0JveCBTeW5jL2NvbGxpZGluZyByYW5nZXMvU2ltdWxhdGlvbnNfaHVtYW5zL1Jlc3VsdHMvYXZhaWxhYmxlIGRhaWx5IHN1bW1hcmllcy9Gb3VyX21vZGVsX2NvbXBhcmVfcmVzdWx0c19leHRpbmN0XyIsIGZvcm1hdChTeXMudGltZSgpLCBmb3JtYXQ9IiVkXyViXyVZIiksIl9jcm9wX3RvXyIsIGNyb3AsIi5SZGF0YSIpKQoKYGBgCgoKYGBge3J9CmxvYWQoJ34vQm94IFN5bmMvY29sbGlkaW5nIHJhbmdlcy9TaW11bGF0aW9uc19odW1hbnMvUmVzdWx0cy9hdmFpbGFibGUgZGFpbHkgc3VtbWFyaWVzL0ZvdXJfbW9kZWxfY29tcGFyZV9yZXN1bHRzXzAyX01hcl8yMDE3X2Nyb3BfdG9fMzQ4MS5SZGF0YScpCmV4dGFudCA8LSBDb25jYXRlbmF0ZWRfZGF0YQpleHRhbnQKYGBgCgoKCgpgYGB7cn0Kc2V0d2QoIn4vQm94IFN5bmMvY29sbGlkaW5nIHJhbmdlcy9TaW11bGF0aW9uc19odW1hbnMvUmVzdWx0cy9hdmFpbGFibGUgZGFpbHkgc3VtbWFyaWVzIikKZGV0YWlscyA8LSBmaWxlLmluZm8obGlzdC5maWxlcygpKQoKdHJpbW1lZF9kZXRhaWxzIDwtIGRldGFpbHNbd2hpY2gobGlzdC5maWxlcygpID09IGxpc3QuZmlsZXMocGF0dGVybiA9ICJGb3VyX21vZGVsX2NvbXBhcmVfcmVzdWx0c19leHRpbmN0KiIpKSxdCm9yZCA8LSBvcmRlcih0cmltbWVkX2RldGFpbHMkbXRpbWUsIGRlY3JlYXNpbmcgPSBUUlVFKQpyb3duYW1lcyh0cmltbWVkX2RldGFpbHNbb3JkLF0pWzFdCmxvYWQocm93bmFtZXModHJpbW1lZF9kZXRhaWxzW29yZCxdKVsxXSkKZXh0aW5jdCA8LSBDb25jYXRlbmF0ZWRfZGF0YQoKdHJpbW1lZF9kZXRhaWxzIDwtIGRldGFpbHNbd2hpY2gobGlzdC5maWxlcygpICE9IGxpc3QuZmlsZXMocGF0dGVybiA9ICJGb3VyX21vZGVsX2NvbXBhcmVfcmVzdWx0c19leHRpbmN0KiIpKSxdCm9yZCA8LSBvcmRlcih0cmltbWVkX2RldGFpbHMkbXRpbWUsIGRlY3JlYXNpbmcgPSBUUlVFKQpyb3duYW1lcyh0cmltbWVkX2RldGFpbHNbb3JkLF0pWzFdCmxvYWQocm93bmFtZXModHJpbW1lZF9kZXRhaWxzW29yZCxdKVsxXSkKZXh0YW50IDwtIENvbmNhdGVuYXRlZF9kYXRhCgoKCgoKYGBgCgpgYGB7cn0KZGltKGV4dGluY3QpCmRpbShleHRhbnQpCmBgYAoKCgoKYGBge3J9Cgpmb3IoaSBpbiBjKDksMTAsMTEsMTIsMTQsMTUsMTYsMTcsMTksMjAsMjEsMjIsMjQsMjUsMjYsMjcsMjksMzAsMzEsMzIpKXsKCWV4dGluY3Rbd2hpY2goaXMubmFuKGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLCBpXSkpKSA9PSBUUlVFKSwgaV0gPC0gTkEKfQoKZm9yKGkgaW4gYyg5LDEwLDExLDEyLDE0LDE1LDE2LDE3LDE5LDIwLDIxLDIyLDI0LDI1LDI2LDI3LDI5LDMwLDMxLDMyKSl7CglleHRhbnRbd2hpY2goaXMubmFuKGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssIGldKSkpID09IFRSVUUpLCBpXSA8LSBOQQp9CgppIDwtIDE5CmZvcihpIGluIGMoMjAsMjEsMjQsMjUsMjYsMjcpKXsKCWV4dGluY3Rbd2hpY2goYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIGldKSkgPT0gMCksIGldIDwtIE5BCn0KCmZvcihpIGluIGMoMjAsMjEsMjQsMjUsMjYsMjcpKXsKCWV4dGFudFt3aGljaChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRhbnRbLCBpXSkpID09IDApLCBpXSA8LSBOQQp9CgoKeGxpbWl0IDwtIGMoMCwxKQp5bGltaXQgPC0gYygwLDYwMCkKbWFpbmNleCA8LSAwLjkKCnBuZyhmaWxlPSJHbG9iYWxfc3VjY2Vzc19yYXRlX3Blcl9wYXJhbWV0ZXIucG5nIiwgd2lkdGg9OC41LCBoZWlnaHQ9MTEsIHVuaXRzPSJpbiIsIHJlcz0zMDApCgpwYXIobWZyb3c9Yyg1LDQpLCBtYXI9YygzLDMsMywwKSkKCgpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLDldKSksIG1haW49InNwZWNpYXRpb24gb2YgRiBpbiBGIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9MC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50Wyw5XSkpLCBtYWluPSJzcGVjaWF0aW9uIG9mIEYgaW4gRiBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9MC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssMTBdKSksIG1haW49InNwZWNpYXRpb24gb2YgRCBpbiBGIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssMTBdKSksIG1haW49InNwZWNpYXRpb24gb2YgRCBpbiBGIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssMTFdKSksIG1haW49InNwZWNpYXRpb24gb2YgRiBpbiBEIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssMTFdKSksIG1haW49InNwZWNpYXRpb24gb2YgRiBpbiBEIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0WywxMl0pKSwgbWFpbj0ic3BlY2lhdGlvbiBvZiBEIGluIEQgZW52IiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywxMl0pKSwgbWFpbj0ic3BlY2lhdGlvbiBvZiBEIGluIEQgZW52IiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCwgYWRkPVRSVUUpCgojIyMjIyMjCgpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLCAxNF0pKSwgbWFpbj0iZXh0aW5jdGlvbiBvZiBGIGluIEYgZW52IiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgMTRdKSksIG1haW49ImV4dGluY3Rpb24gb2YgRiBpbiBGIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKCgpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLCAxNV0pKSwgbWFpbj0iZXh0aW5jdGlvbiBvZiBEIGluIEYgZW52IiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgMTVdKSksIG1haW49ImV4dGluY3Rpb24gb2YgRCBpbiBGIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0WywgMTZdKSksIG1haW49ImV4dGluY3Rpb24gb2YgRiBpbiBEIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssIDE2XSkpLCBtYWluPSJleHRpbmN0aW9uIG9mIEYgaW4gRCBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDE3XSkpLCBtYWluPSJleHRpbmN0aW9uIG9mIEQgaW4gRCBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCkKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRhbnRbLCAxN10pKSwgbWFpbj0iZXh0aW5jdGlvbiBvZiBEIGluIEQgZW52IiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCwgYWRkPVRSVUUpCgojIyMjIyMKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDI5XSkpLCBtYWluPSJhcmlzYWwgb2YgRiBpbiBGIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssIDI5XSkpLCBtYWluPSJhcmlzYWwgb2YgRiBpbiBGIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKCgpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLCAzMF0pKSwgbWFpbj0iYXJpc2FsIG9mIEQgaW4gRiBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCkKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRhbnRbLCAzMF0pKSwgbWFpbj0iYXJpc2FsIG9mIEQgaW4gRiBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDMxXSkpLCBtYWluPSJhcmlzYWwgb2YgRiBpbiBEIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssIDMxXSkpLCBtYWluPSJhcmlzYWwgb2YgRiBpbiBEIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0WywgMzJdKSksIG1haW49ImFyaXNhbCBvZiBEIGluIEQgZW52IiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgMzJdKSksIG1haW49ImFyaXNhbCBvZiBEIGluIEQgZW52IiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCwgYWRkPVRSVUUpCgojIyMjIyMKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDE5XSkpLCBtYWluPSJOT1BFIC0tIERpZmZ1c2lvbjogc291cmNlIEYsIHRhcmdldCBGIiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IGMoMCwxODAwMCksIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssIDE5XSkpLCBtYWluPSJOT1BFIC0tIERpZmZ1c2lvbjogc291cmNlIEYsIHRhcmdldCBGIiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0gYygwLDE4MDAwKSwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKCgpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLCAyMF0pKSwgbWFpbj0iRGlmZnVzaW9uOiBzb3VyY2UgRCwgdGFyZ2V0IEYiLCBjb2w9YWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCkKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRhbnRbLCAyMF0pKSwgbWFpbj0iRGlmZnVzaW9uOiBzb3VyY2UgRCwgdGFyZ2V0IEYiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDIxXSkpLCBtYWluPSJEaWZmdXNpb246IHNvdXJjZSBGLCB0YXJnZXQgRCIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssIDIxXSkpLCBtYWluPSJEaWZmdXNpb246IHNvdXJjZSBGLCB0YXJnZXQgRCIsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0WywgMjJdKSksIG1haW49Ik5PUEUgLS0gRGlmZnVzaW9uOiBzb3VyY2UgRCwgdGFyZ2V0IEQiLCBjb2w9YWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0gYygwLDE4MDAwKSwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgMjJdKSksIG1haW49Ik5PUEUgLS0gRGlmZnVzaW9uOiBzb3VyY2UgRCwgdGFyZ2V0IEQiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSBjKDAsMTgwMDApLCBjZXgubWFpbj0gbWFpbmNleCwgYWRkPVRSVUUpCgojIyMjCgpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLCAyNF0pKSwgbWFpbj0iVGFrZW92ZXI6IHNvdXJjZSBGLCB0YXJnZXQgRiIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssIDI0XSkpLCBtYWluPSJUYWtlb3Zlcjogc291cmNlIEYsIHRhcmdldCBGIiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCwgYWRkPVRSVUUpCgoKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDI1XSkpLCBtYWluPSJUYWtlb3Zlcjogc291cmNlIEQsIHRhcmdldCBGIiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgMjVdKSksIG1haW49IlRha2VvdmVyOiBzb3VyY2UgRCwgdGFyZ2V0IEYiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDI2XSkpLCBtYWluPSJUYWtlb3Zlcjogc291cmNlIEYsIHRhcmdldCBEIiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgMjZdKSksIG1haW49IlRha2VvdmVyOiBzb3VyY2UgRiwgdGFyZ2V0IEQiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDI3XSkpLCBtYWluPSJUYWtlb3Zlcjogc291cmNlIEQsIHRhcmdldCBEIiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgMjddKSksIG1haW49IlRha2VvdmVyOiBzb3VyY2UgRCwgdGFyZ2V0IEQiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCgpkZXYub2ZmKCkKCgoKCgoKYGBgCgoKIVtdKEdsb2JhbF9zdWNjZXNzX3JhdGVfcGVyX3BhcmFtZXRlci5wbmcpCgoKYGBge3J9CgoKCnBuZyhmaWxlPSJleHRpY3Rpb24gbWludXMgZXh0YW50IHBlciBvdXRjb21lLnBuZyIsIHdpZHRoPTguNSwgaGVpZ2h0PTExLCB1bml0cz0iaW4iLCByZXM9MzAwKQpwYXIobWZyb3c9YygzLDEpKQoKcGxvdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0Wyw5XSkpLCBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0WywxNF0pKSwgeGxhYj0ic3BlY2lhdGlvbiIsIHlsYWI9ImV4dGluY3Rpb24iLCBjb2w9IGFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0wLjIpLCBwY2g9MTksIGNleD0wLjYsIHlsaW09YygwLDEpKQpwbG90KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssOV0pKSwgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywxNF0pKSwgeGxhYj0ic3BlY2lhdGlvbiIsIHlsYWI9ImV4dGluY3Rpb24iLCBjb2w9IGFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPTAuMiksIHBjaD0xOSwgY2V4PTAuNiwgeWxpbT1jKDAsMSkpCgpwbG90KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLDldKSksIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLDE0XSkpLCB4bGFiPSJzcGVjaWF0aW9uIiwgeWxhYj0iZXh0aW5jdGlvbiIsIGNvbD0gYWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPTAuMiksIHBjaD0xOSwgY2V4PTAuNiwgeWxpbT1jKDAsMSkpCnBvaW50cyhhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRhbnRbLDldKSksIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssMTRdKSksIHhsYWI9InNwZWNpYXRpb24iLCB5bGFiPSJleHRpbmN0aW9uIiwgY29sPSBhZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0wLjIpLCBwY2g9MTksIGNleD0wLjYpCgoKZGV2Lm9mZigpCgoKYGBgCgohW10oZXh0aWN0aW9uIG1pbnVzIGV4dGFudCBwZXIgb3V0Y29tZS5wbmcpCgoKCmBgYHtyfQoKcGFyYW1zIDwtIGV4dGFudFssLTE6LTM1XQpuYW1lcyhwYXJhbXMpCmJyZWFrX251bWJlciA8LSAxMAp4bWluIDwtCnhtYXggPC0gCgp4MSA8LSBhcy5udW1lcmljKHBhcmFtc1ssMV0pCmgxIDwtIGhpc3QoeDEsICBwbG90PUZBTFNFLCBicmVha3M9IGJyZWFrX251bWJlcikKeGZpdDEgPC0gc2VxKHhtaW4sIHhtYXgsIGxlbmd0aD0gMTAwKQp5Zml0MSA8LSBkbm9ybSh4Zml0MSwgbWVhbj1tZWFuKHgxKSwgc2Q9c2QoeDEpKQp5Zml0MSA8LSB5Zml0MSpkaWZmKGgxJG1pZHNbMToyXSkqbGVuZ3RoKHgxKSsxMDEuNQpwb2x5Z29uKHhmaXQxLCB5Zml0MSwgY29sPWFkanVzdGNvbG9yKCJsaW1lZ3JlZW4iLCBhbHBoYT0wLjUpLCBsd2Q9MiwgYm9yZGVyPWFkanVzdGNvbG9yKCJsaW1lZ3JlZW4iLCBhbHBoYT0wLjYpKQoKYGBgCgoKCgoKYGBge3J9CgpzZXR3ZCgifi9Cb3ggU3luYy9jb2xsaWRpbmcgcmFuZ2VzL1NpbXVsYXRpb25zX2h1bWFucy9SZXN1bHRzL2F2YWlsYWJsZSBkYWlseSBzdW1tYXJpZXMiKQpkZXRhaWxzIDwtIGZpbGUuaW5mbyhsaXN0LmZpbGVzKCkpCgp0cmltbWVkX2RldGFpbHMgPC0gZGV0YWlsc1t3aGljaChsaXN0LmZpbGVzKCkgPT0gbGlzdC5maWxlcyhwYXR0ZXJuID0gIkZvdXJfbW9kZWxfY29tcGFyZV9yZXN1bHRzX2V4dGluY3QqIikpLF0Kb3JkIDwtIG9yZGVyKHRyaW1tZWRfZGV0YWlscyRtdGltZSwgZGVjcmVhc2luZyA9IFRSVUUpCnJvd25hbWVzKHRyaW1tZWRfZGV0YWlsc1tvcmQsXSlbMV0KbG9hZChyb3duYW1lcyh0cmltbWVkX2RldGFpbHNbb3JkLF0pWzFdKQpleHRpbmN0IDwtIENvbmNhdGVuYXRlZF9kYXRhCgp0cmltbWVkX2RldGFpbHMgPC0gZGV0YWlsc1t3aGljaChsaXN0LmZpbGVzKCkgIT0gbGlzdC5maWxlcyhwYXR0ZXJuID0gIkZvdXJfbW9kZWxfY29tcGFyZV9yZXN1bHRzX2V4dGluY3QqIikpLF0Kb3JkIDwtIG9yZGVyKHRyaW1tZWRfZGV0YWlscyRtdGltZSwgZGVjcmVhc2luZyA9IFRSVUUpCnJvd25hbWVzKHRyaW1tZWRfZGV0YWlsc1tvcmQsXSlbMV0KbG9hZChyb3duYW1lcyh0cmltbWVkX2RldGFpbHNbb3JkLF0pWzFdKQpleHRhbnQgPC0gQ29uY2F0ZW5hdGVkX2RhdGEKCgoKbG9hZCgnfi9Cb3ggU3luYy9jb2xsaWRpbmcgcmFuZ2VzL1NpbXVsYXRpb25zX2h1bWFucy9BdmFpbGFibGUgdHJlZXMvcmVhbC5hbmFseXNpcy5SRGF0YScpCgpDb25jYXRlbmF0ZWRfZGF0YSA8LSBleHRhbnQKaGVhZChDb25jYXRlbmF0ZWRfZGF0YSkKI0NvbmNhdGVuYXRlZF9kYXRhIDwtIENvbmNhdGVuYXRlZF9kYXRhW0NvbmNhdGVuYXRlZF9kYXRhWywgMl0gPT0gInN0YXRzLm5vLmJUTyIsIF0KI0NvbmNhdGVuYXRlZF9kYXRhIDwtIENvbmNhdGVuYXRlZF9kYXRhW0NvbmNhdGVuYXRlZF9kYXRhWywgNl0gIT0gIjA1IiwgXQojIENvbmNhdGVuYXRlZF9kYXRhWywgNl0gPC0gYXMubnVtZXJpYyhDb25jYXRlbmF0ZWRfZGF0YVssIDZdKQojICMgQ29uY2F0ZW5hdGVkX2RhdGFbb3JpZ2luYWxbLCAyXSA9PSAiYmFja2dyb3VuZF90YWtlb3ZlciIsIDZdIDwtICBDb25jYXRlbmF0ZWRfZGF0YVtvcmlnaW5hbFssIDJdID09ICJiYWNrZ3JvdW5kX3Rha2VvdmVyIiwgNl0gKyA0CkNvbmNhdGVuYXRlZF9kYXRhWywgNl0gPC0gZmFjdG9yKENvbmNhdGVuYXRlZF9kYXRhWywgNl0pCiNoZWFkKENvbmNhdGVuYXRlZF9kYXRhKQojbmFtZXMoQ29uY2F0ZW5hdGVkX2RhdGEpCgpQQ0FkYXRhIDwtIENvbmNhdGVuYXRlZF9kYXRhWywgLSgxOjM1KV0KUENBZGF0YSA8LSBQQ0FkYXRhWywgLTEyXQpQQ0FkYXRhIDwtIGFwcGx5KFBDQWRhdGEsIDIsIGFzLm51bWVyaWMpCnJlbW92ZSA8LSBhcHBseShpcy5uYShQQ0FkYXRhKSwgMSwgYW55KQpQQ0FkYXRhIDwtIFBDQWRhdGFbIXJlbW92ZSwgXQoKIyBQcmVkaWN0aW9ucwpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkKCmRhdGEuYW5hbHlzaXMuY29tcDIgPC0gZGF0YS5mcmFtZSgiTW9kZWwiID0gYXMuZmFjdG9yKENvbmNhdGVuYXRlZF9kYXRhWyFyZW1vdmUsIDZdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBDQWRhdGEpCmRhdGEuYW5hbHlzaXMuY29tcDIkc3ByYXRlIDwtIGRhdGEuYW5hbHlzaXMuY29tcDIkdHJhaXRfMV9zcGVjaWF0aW9uL2RhdGEuYW5hbHlzaXMuY29tcDIkdHJhaXRfMl9zcGVjaWF0aW9uCmRhdGEuYW5hbHlzaXMuY29tcDIkZXh0cmF0ZSA8LSBkYXRhLmFuYWx5c2lzLmNvbXAyJHRyYWl0XzFfZXh0aW5jdGlvbi9kYXRhLmFuYWx5c2lzLmNvbXAyJHRyYWl0XzJfZXh0aW5jdGlvbgoKCiNsb2FkKCJSZWFsX3BoeS9yZWFsLmFuYWx5c2lzLlJEYXRhIikKYSA8LSBhcy5kYXRhLmZyYW1lKHJlYWwuYW5hbHlzaXMkcmVzdWx0c19zdW1tYXJ5X29mX3NpbmdsZV92YWx1ZV9vdXRwdXRzKQphJHNwcmF0ZSA8LSBhJHRyYWl0XzFfc3BlY2lhdGlvbiAvIGEkdHJhaXRfMl9zcGVjaWF0aW9uCmEkZXh0cmF0ZSA8LSBhJHRyYWl0XzFfZXh0aW5jdGlvbiAvIGEkdHJhaXRfMl9leHRpbmN0aW9uCgpkYXRhLmFuYWx5c2lzLmNvbXAzIDwtIGRhdGEuYW5hbHlzaXMuY29tcDJbLCAtYygyLCAxMzoxNCwgMTY6MjApXQojZGF0YS5hbmFseXNpcy5jb21wMyA8LSBkYXRhLmFuYWx5c2lzLmNvbXAzW2RhdGEuYW5hbHlzaXMuY29tcDMkTW9kZWwgJWluJSAxOjQsIF0KI2RhdGEuYW5hbHlzaXMuY29tcDMkTW9kZWwgPC0gZmFjdG9yKGRhdGEuYW5hbHlzaXMuY29tcDMkTW9kZWwpCiNzdWIgPC0gdW5saXN0KGxhcHBseShhcy5saXN0KGMoMTo0KSksIGZ1bmN0aW9uKHgsIHkpIHsKIyAgc2FtcGxlKHdoaWNoKHkkTW9kZWwgPT0geCksIG1pbih0YWJsZShkYXRhLmFuYWx5c2lzLmNvbXAzJE1vZGVsKSkpfSwKIyAgeSA9IGRhdGEuYW5hbHlzaXMuY29tcDMpKQojIGRhdGEuYW5hbHlzaXMuY29tcDMgPC0gZGF0YS5hbmFseXNpcy5jb21wM1tzdWIsIF0KZnVuIDwtIGZ1bmN0aW9uKHgsIHksIHBlciA9IC4zMykge3NhbXBsZSh3aGljaCh5JE1vZGVsID09IHgpLCByb3VuZCh0YWJsZSh5JE1vZGVsKVsxXSpwZXIpKX0KCnN1Yi50ZXN0IDwtIHVubGlzdChsYXBwbHkoYXMubGlzdChwYXN0ZTAoMCwgYygxOjQpKSksIGZ1biwKICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gZGF0YS5hbmFseXNpcy5jb21wMykpCnRlc3QyIDwtIGRhdGEuYW5hbHlzaXMuY29tcDNbc3ViLnRlc3QsIDI6bmNvbChkYXRhLmFuYWx5c2lzLmNvbXAzKV0KdGVzdDEgPC0gZGF0YS5hbmFseXNpcy5jb21wM1tzdWIudGVzdCwgMV0KdHJhaW4gPC0gZGF0YS5hbmFseXNpcy5jb21wM1stc3ViLnRlc3QsIF0KCnRyYWluWywgLTFdIDwtIGFwcGx5KHRyYWluWywgLTFdLCAyLCBhcy5udW1lcmljKQp0ZXN0MiA8LSBhcy5kYXRhLmZyYW1lKGFwcGx5KHRlc3QyLCAyLCBhcy5udW1lcmljKSkKaW5maW5pdGVzIDwtIHdoaWNoKGFwcGx5KHRyYWluWywgLTFdLCAyLCBpcy5pbmZpbml0ZSksIGFyci5pbmQ9VCkKaWYgKG5yb3coaW5maW5pdGVzKSA+IDApIHsKdHJhaW4gPC0gdHJhaW5bLWluZmluaXRlc1ssIDFdLCBdCn0KaW5maW5pdGVzMiA8LSB3aGljaChhcHBseSh0ZXN0MiwgMiwgaXMuaW5maW5pdGUpLCBhcnIuaW5kPVQpCmlmIChucm93KGluZmluaXRlczIpID4gMCkgewp0ZXN0MiA8LSB0ZXN0MlstaW5maW5pdGVzMlssIDFdLCBdCnRlc3QxIDwtIHRlc3QxWy1pbmZpbml0ZXMyWywgMV1dCn0KCgpmb3IoaSBpbiAxOjEwMCl7CihmaXQgPC0gcmFuZG9tRm9yZXN0KE1vZGVsIH4gLiwgZGF0YT10cmFpbiwgeHRlc3QgPSB0ZXN0MiwgeXRlc3QgPSB0ZXN0MSwgCiAgICAgICAgICAgICAgICAgICAgaW1wb3J0YW5jZT1UUlVFLCBudHJlZT0xMDAwLCBrZWVwLmZvcmVzdCA9IFRSVUUsIHJlcGxhY2U9RkFMU0UpKQoKcHJlZGljdGlvbnMgPC0gcHJlZGljdChmaXQsIAogICAgICAgICAgICAgICAgICAgICAgIGEsCiAgICAgICAgICAgICAgICAgICAgICAgdHlwZT0icHJvYiIpCnByZWRpY3Rpb25zCgpzYXZlKGZpdCwgZmlsZT1wYXN0ZTAoIn4vQm94IFN5bmMvY29sbGlkaW5nIHJhbmdlcy9TaW11bGF0aW9uc19odW1hbnMvUmVzdWx0cy9SRl9kYWlseV9vdXRwdXQvUkZfZGFpbHlfb3V0cHV0XyIsIGZvcm1hdChTeXMudGltZSgpLCBmb3JtYXQ9IiVkXyViXyVZIiksICJfIixpLCAiX05vUkVQTEFDRU1FTlRfLlJkYXRhIikpCn0KYGBgCgpgYGB7cn0KCgpzYXZlKGZpdCwgZmlsZT1wYXN0ZTAoIn4vQm94IFN5bmMvY29sbGlkaW5nIHJhbmdlcy9TaW11bGF0aW9uc19odW1hbnMvUmVzdWx0cy9SRl9kYWlseV9vdXRwdXQvUkZfZGFpbHlfb3V0cHV0XyIsIGZvcm1hdChTeXMudGltZSgpLCBmb3JtYXQ9IiVkXyViXyVZIiksIi5SZGF0YSIpKQpgYGAKCgoKCmBgYHtyfQoKcGxvdChmaXQsIHlsaW09YygwLDEpKQoKYGBgCgoKCgpgYGB7cn0KbGFicyA8LSBjKCJCYXNpYyIsICIrRGlmZnVzaW9uIiwgIitUYWtlb3ZlciIsICIrRGlmZnVzaW9uICtUYWtlb3ZlciIpCgpgYGAKCgpgYGB7cn0KIyBiYXIgcGxvdApwbmcoIlByb2JfYXVzLnBuZyIsIHdpZHRoID0gMjUsIGhlaWdodCA9IDI1LCByZXMgPSAzMDAsIHVuaXRzID0gImluIikKcGFyKG1hciA9IGMoOCwgOCwgMSwgMSkpCnByZWQgPC0gc2V0TmFtZXMoYXMubnVtZXJpYyhwcmVkaWN0aW9ucyksIGxhYnMpCmNvbHMgPC0gcmV2KGMoImRhcmtncmVlbiIsICJyZWQiLCAiYmx1ZSIsICJkYXJrb3JhbmdlMSIpKQpiYXJwbG90KHByZWQsIGNvbCA9IGNvbHMsIHlsYWIgPSAiUHJvYWJpbGl0eSIsIGNleC5sYWIgPSAzLCBjZXgubmFtZXMgPSAyKQpkZXYub2ZmKCkKYGBgCgohW10oUHJvYl9hdXMucG5nKQoKCmBgYHtyfQojIFBsb3QgY29uZnVzaW9uIG1hdHJpeApwbmcoIkNvbmZmdXNpb25fbWF0cml4X2FsbC5wbmciLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSAyNSwgcmVzPTMwMCwgdW5pdHM9ImluIikKcGFyKG1hciA9IGMoMTAsIDExLCAxLCAxKSkKY29sb3JzMSA8LSBjb2xvclJhbXBQYWxldHRlKGNvbG9ycyA9IGMoIiNmMGYwZjAiLCAiI2JkYmRiZCIsIiM2MzYzNjMiKSkKcHJvcCA8LSBhcHBseShmaXQkY29uZnVzaW9uWywgLTVdLCAyLCBmdW5jdGlvbih4KXt4IC8gc3VtKHgpfSkgKiAxMDAKCmltYWdlKHByb3AsIGNvbCA9IGNvbG9yczEoMjApLCBheGVzPUZBTFNFKQpheGlzKDEsIGF0PWMoMCwgLjMzLCAuNjYsIDEpLCBsYWJlbHM9bGFicywgdGljayA9IEZBTFNFLCBsaW5lID0gRkFMU0UsIGNleC5heGlzID0gMy41LCBwb3MgPSAtLjE5KQpheGlzKDIsIGF0PWMoMCwgLjMzLCAuNjYsIDEpLCBsYWJlbHM9bGFicywgdGljayA9IEZBTFNFLCBsaW5lID0gRkFMU0UsIGNleC5heGlzID0gMy41KQptdGV4dCgiQUNUVUFMIiwgc2lkZSA9IDEsIHBhZGogPSAzLCBjZXggPSA0KQptdGV4dCgiUFJFRElDVEVEIiwgc2lkZSA9IDIsIHBhZGogPSAtMywgY2V4ID0gNCkKCmZvcihpIGluIDE6NCkgewogIGZvcihqIGluIDE6NCkgewogICAgdGV4dCh4ID0gYygwLCAuMzMsIC42NiwgMSlbaV0sIHkgPSBjKDAsIC4zMywgLjY2LCAxKVtqXSwgcGFzdGUwKHJvdW5kKHByb3BbaSwgal0sIDIpLCAiJSIpLAogICAgICAgICBjZXggPSA1KQogIH0KfQpkZXYub2ZmKCkKYGBgCgoKIVtdKENvbmZmdXNpb25fbWF0cml4X2FsbC5wbmcpCgoKYGBge3J9CmltcG9ydGFuY2UoZml0KQpgYGAKCgpgYGB7cn0KIyBWYXJpYWJsZXMgaW1wb3J0YW5jZQoKaW1wIDwtIGltcG9ydGFuY2UoZml0KQppbXAgPC0gYXBwbHkoaW1wLCAyLCBmdW5jdGlvbih4KSAoeCAtIG1pbih4KSkvKG1heCh4KSAtIG1pbih4KSkpCmltcCA8LSBpbXBbc29ydChpbXBbLCA1XSwgaW5kZXgucmV0dXJuID0gVFJVRSwgZGVjcmVhc2luZyA9IFRSVUUpJGl4LCBdCgoKbmFtZXMgPC0gcm93bmFtZXMoaW1wKQpuYW1lc1tuYW1lcyA9PSAic3BhdGlhbC50ZXN0cy5mb3JhIl0gPC0gIlNwYWNlIEYiCm5hbWVzW25hbWVzID09ICJzcGF0aWFsLnRlc3RzLmRvbSJdIDwtICJTcGFjZSBEIgpuYW1lc1tuYW1lcyA9PSAic3ByYXRlIl0gPC0gIlNwKHJhdGlvKSIKbmFtZXNbbmFtZXMgPT0gInRyYW5zaXRpb25fZnJvbV90cmFpdF8xX3RvXzIiXSA8LSAiVFIoMS0yKSIKbmFtZXNbbmFtZXMgPT0gInRyYW5zaXRpb25fZnJvbV90cmFpdF8yX3RvXzEiXSA8LSAiVFIoMi0xKSIKbmFtZXNbbmFtZXMgPT0gIlBoeWxvZ2VuZXRpY19zaWduYWwiXSA8LSAiUGh5U2lnKEQpIgpuYW1lc1tuYW1lcyA9PSAiRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzc19zdW0iXSA8LSAiRURzdW0iCm5hbWVzW25hbWVzID09ICJQeWxvX2RpdmVyc2l0eV9pc19zdW1fb2ZfQkwiXSA8LSAiUERzdW0iCm5hbWVzW25hbWVzID09ICJ0cmFuc2l0aW9uX3JhdGVfcmF0aW9fMXRvMl9vdmVyXzJ0bzEiXSA8LSAiVFIocmF0aW8pIgpuYW1lc1tuYW1lcyA9PSAiZ2FtbWEiXSA8LSAiR2FtbWEiCm5hbWVzW25hbWVzID09ICJtZWFuX1BoeWxvZ2VuZXRpY19pc29sYXRpb24iXSA8LSAiTVBJIgpuYW1lc1tuYW1lcyA9PSAiZXh0cmF0ZSJdIDwtICJFeHQocmF0aW8pIgpuYW1lc1tuYW1lcyA9PSAiYXZlcmFnZV9waHlsb2dlbmV0aWNfZGl2ZXJzaXR5X2lzX21lYW5fb2ZfQkwiXSA8LSAiUERtZWFuIgpuYW1lc1tuYW1lcyA9PSAiZXh0aW5jdGlvbl9wZXJfc3BlY2lhdGlvbiJdIDwtICJEUiIKbmFtZXNbbmFtZXMgPT0gInZhcmlhbmNlX1BoeWxvZ2VuZXRpY19pc29sYXRpb24iXSA8LSAiVlBJIgpuYW1lc1tuYW1lcyA9PSAiRl9xdWFkcmF0aWNfZW50cm9weV9pc19zdW1fb2ZfUEQiXSA8LSAiRiIKbmFtZXNbbmFtZXMgPT0gIk1lYW5fcGFpcndpc2VfZGlzdGFuY2UiXSA8LSAiTVBEIgpuYW1lc1tuYW1lcyA9PSAidmFyaWFuY2VfUHlsb19kaXZlcnNpdHlfaXNfdmFyaWFuY2Vfb2ZfQkwiXSA8LSAiUER2YXIiCm5hbWVzW25hbWVzID09ICJ2YXJpYW5jZV9wYWlyd2lzZV9kaXN0YW5jZSJdIDwtICJWUEQiCgoKcG5nKCJ2YXJfaW1wb3J0X2FsbC5wbmciLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSAyNSwgdW5pdD0iaW4iLCByZXM9MzAwKQpwYXIobWFyID0gYygxMCwgMTgsIDEsIDEpKQpwbG90KHggPSByZXYoaW1wWywgNV0pLCB5ID0gMTpucm93KGltcCksIHR5cGUgPSAibCIsIHlheHQgPSAibiIsIAogICAgIHlsYWIgPSAiIiwgeGxhYiA9ICJWYXJpYWJsZSBJbXBvcnRhbmNlIiwKICAgICB4bGltID0gYygwLCAxKSwgbHdkID0gMiwgY2V4LmxhYiA9IDQpCmZvciAoaSBpbiAxOm5yb3coaW1wKSkgewogIGFibGluZShoID0gaSwgbHR5ID0gMywgY29sID0gImdyYXk4MCIpCn0KYWJsaW5lKHYgPSBzZXEoMCwgMSwgMS8xOSksIGx0eSA9IDMsIGNvbCA9ICJncmF5ODAiKQoKbGluZXMoeCA9IHJldihpbXBbLCA0XSksIHkgPSAxOm5yb3coaW1wKSwgY29sID0gImRhcmtncmVlbiIsIGx3ZCA9IDIpCmxpbmVzKHggPSByZXYoaW1wWywgM10pLCB5ID0gMTpucm93KGltcCksIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQpsaW5lcyh4ID0gcmV2KGltcFssIDJdKSwgeSA9IDE6bnJvdyhpbXApLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpCmxpbmVzKHggPSByZXYoaW1wWywgMV0pLCB5ID0gMTpucm93KGltcCksIGNvbCA9ICJkYXJrb3JhbmdlMSIsIGx3ZCA9IDIpCmxpbmVzKHggPSByZXYoaW1wWywgNV0pLCB5ID0gMTpucm93KGltcCksIGx3ZCA9IDMpCgpwb2ludHMoeCA9IHJldihpbXBbLCA0XSksIHkgPSAxOm5yb3coaW1wKSwgY29sID0gImRhcmtncmVlbiIsIGNleCA9IDIpCnBvaW50cyh4ID0gcmV2KGltcFssIDNdKSwgeSA9IDE6bnJvdyhpbXApLCBjb2wgPSAicmVkIiwgY2V4ID0gMikKcG9pbnRzKHggPSByZXYoaW1wWywgMl0pLCB5ID0gMTpucm93KGltcCksIGNvbCA9ICJibHVlIiwgY2V4ID0gMikKcG9pbnRzKHggPSByZXYoaW1wWywgMV0pLCB5ID0gMTpucm93KGltcCksIGNvbCA9ICJkYXJrb3JhbmdlMSIsIGNleCA9IDIpCnBvaW50cyh4ID0gcmV2KGltcFssIDVdKSwgeSA9IDE6bnJvdyhpbXApLCBwY2ggPSAyMCwgY2V4ID0gMykKCgp0ZXh0KHkgPSAxOm5yb3coaW1wKSwgeCA9IHBhcigidXNyIilbMV0gLSAuMTcsIGxhYmVscyA9IHJldihuYW1lcyksCiAgICAgc3J0ID0gMCwgcG9zID0gNCwgeHBkID0gVCwgY2V4ID0gNCkKZGV2Lm9mZigpCmBgYAoKIVtdKHZhcl9pbXBvcnRfYWxsLnBuZykKCgoKCmBgYHtyfQpwYXIobWZyb3c9YygyLDMpKQoKIyBCb3ggcGxvdHMKYm94cGxvdChzcGF0aWFsLnRlc3RzLmZvcmEgfiBNb2RlbCwgZGF0YSA9IGRhdGEuYW5hbHlzaXMuY29tcDMpCmFibGluZShoID0gYSRzcGF0aWFsLnRlc3RzLmZvcmEsIGNvbCA9ICJyZWQiLCBsdHkgPSAyKQoKYm94cGxvdChzcGF0aWFsLnRlc3RzLmRvbSB+IE1vZGVsLCBkYXRhID0gZGF0YS5hbmFseXNpcy5jb21wMykKYWJsaW5lKGggPSBhJHNwYXRpYWwudGVzdHMuZm9yYSwgY29sID0gInJlZCIsIGx0eSA9IDIpCgpib3hwbG90KGxvZyhzcHJhdGUpIH4gTW9kZWwsIGRhdGEgPSBkYXRhLmFuYWx5c2lzLmNvbXAzLCB5bGltID0gYygtMTAsIDEwKSkKYWJsaW5lKGggPSBsb2coYSRzcHJhdGUpLCBjb2wgPSAicmVkIiwgbHR5ID0gMikKCmJveHBsb3QobG9nKGV4dHJhdGUpIH4gTW9kZWwsIGRhdGEgPSBkYXRhLmFuYWx5c2lzLmNvbXAzLCB5bGltID0gYygtMTAsIDEwKSkKYWJsaW5lKGggPSBsb2coYSRleHRyYXRlKSwgY29sID0gInJlZCIsIGx0eSA9IDIpCgpib3hwbG90KGxvZyh0cmFuc2l0aW9uX3JhdGVfcmF0aW9fMXRvMl9vdmVyXzJ0bzEpIH4gTW9kZWwsIGRhdGEgPSBkYXRhLmFuYWx5c2lzLmNvbXAzKQphYmxpbmUoaCA9IGxvZyhhJHNwcmF0ZSksIGNvbCA9ICJyZWQiLCBsdHkgPSAyKQoKYm94cGxvdChQaHlsb2dlbmV0aWNfc2lnbmFsIH4gTW9kZWwsIGRhdGEgPSBkYXRhLmFuYWx5c2lzLmNvbXAzLCB5bGltID0gYygwLCAxKSkKYWJsaW5lKGggPSBhJFBoeWxvZ2VuZXRpY19zaWduYWwsIGNvbCA9ICJyZWQiLCBsdHkgPSAyKQoKCmBgYAoKCgpgYGB7cn0KI2J1aWxkIGEgZGF0YSB0cmFja2luZyB0YWJsZSB0byB0cmFjayBwYXJhbWV0ZXIgY2hhbmdlcyB0aHJvdWdoIHRpbWUKCnN0cihmaXQpCgp5CgpgYGAKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgo8IS0tY2hhcHRlcjplbmQ6TW9kdWxlXzNfbWFya2Rvd24uUm1kLS0+CgotLS0KdGl0bGU6ICJELXBsYWNlIEZBUk0gZG9jdW1lbnRhdGlvbjogTW9kdWxlIDMgdGhyb3VnaCB0aW1lIgphdXRob3I6ICJUeSBUdWZmLCBCcnVubyBWaWxlbGEsIGFuZCBDYXJsb3MgQm90ZXJvIgpkYXRlOiAncHJvamVjdCBiZWdhbjogMTUgTWF5IDIwMTYsIGRvY3VtZW50IHVwZGF0ZWQ6IGByIHN0cmZ0aW1lKFN5cy50aW1lKCksIGZvcm1hdAogID0gIiVkICVCICVZIilgJwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0CmJpYmxpb2dyYXBoeTogRkFSTSBwYWNrYWdlLmJpYgotLS0KCgpgYGB7cn0Kc2V0d2QoIn4vQm94IFN5bmMvY29sbGlkaW5nIHJhbmdlcy9TaW11bGF0aW9uc19odW1hbnMvUmVzdWx0cy9SRl9kYWlseV9vdXRwdXQiKQoKZGV0YWlscyA8LSBmaWxlLmluZm8obGlzdC5maWxlcygpKQoKdHJpbW1lZF9kZXRhaWxzIDwtIGRldGFpbHNbd2hpY2gobGlzdC5maWxlcygpID09IGxpc3QuZmlsZXMocGF0dGVybiA9ICJGb3VyX21vZGVsX2NvbXBhcmVfcmVzdWx0c19leHRpbmN0KiIpKSxdCm9yZCA8LSBvcmRlcih0cmltbWVkX2RldGFpbHMkbXRpbWUsIGRlY3JlYXNpbmcgPSBUUlVFKQpyb3duYW1lcyh0cmltbWVkX2RldGFpbHNbb3JkLF0pWzFdCmxvYWQocm93bmFtZXModHJpbW1lZF9kZXRhaWxzW29yZCxdKVsxXSkKZXh0aW5jdCA8LSBDb25jYXRlbmF0ZWRfZGF0YQoKCgoKYGBgCgoKYGBge3J9CnN0cihmaXQpCmBgYAoKCmBgYHtyfQpmaXQkY29uZnVzaW9uCmFzLnZlY3RvcihmaXQkY29uZnVzaW9uKQphcy52ZWN0b3IoZml0JHRlc3QkY29uZnVzaW9uKQoKYGBgCgoKYGBge3J9CmZpdCRpbXBvcnRhbmNlWyw1XQpmaXQkaW1wb3J0YW5jZVNEWyw1XQpgYGAKCgoKYGBge3J9CgoKc3RyKGZpdCkKZml0JGNvbmZ1c2lvbgpwbG90KGZpdCRlcnIucmF0ZVssMV0pCmxpbmVzKGZpdCRlcnIucmF0ZVssMl0pCmxpbmVzKGZpdCRlcnIucmF0ZVssM10pCmxpbmVzKGZpdCRlcnIucmF0ZVssNF0pCmxpbmVzKGZpdCRlcnIucmF0ZVssNV0pCgoKYGBgCgo8IS0tY2hhcHRlcjplbmQ6TW9kdWxlXzNfdGhyb3VnaF90aW1lLlJtZC0tPgoKCi0tLQp0aXRsZTogIlRyZWUgYW5kIHNwYWNlIGFuYWx5c2lzIGZ1bmN0aW9uIgphdXRob3I6ICJUeSBUdWZmIGFuZCBCcnVubyBWaWxlbGEiCmRhdGU6ICdgciBzdHJmdGltZShTeXMudGltZSgpLCBmb3JtYXQgPSAiJUIgJWQsICVZIilgJwpvdXRwdXQ6IGh0bWxfZG9jdW1lbnQKLS0tCgoKCgpgYGB7ciB9CmxvYWQoJ34vRG93bmxvYWRzL0ZVTExfVFJFRV9Tb2NpZXR5X2RhdGFfd2l0aF9iaW5hcnlfY29udmVyc2lvbnMuUmRhdGEnKQoKbG9hZCgnfi9Eb3dubG9hZHMvVHJlZV9GVUxMX3RyaW1tZWQuUmRhdGEnKQoKdGhpc190cmVlIDwtIGZ1bGxfdHJlZSAKCgpsb2FkKCd+L0Rvd25sb2Fkcy9kb3dubG9hZC5SZGF0YScpCm9iamVjdHMoKQpzdHIobXlPdXQpCgp0aGlzX3RyZWUgPC0gbXlPdXQkbXl0cmVlCnRoaXNfd29ybGQgPC0gbXlPdXQkbXlXb3JsZApgYGAKCiMjIFIgTWFya2Rvd24KClRoaXMgaXMgYW4gUiBNYXJrZG93biBkb2N1bWVudC4gTWFya2Rvd24gaXMgYSBzaW1wbGUgZm9ybWF0dGluZyBzeW50YXggZm9yIGF1dGhvcmluZyBIVE1MLCBQREYsIGFuZCBNUyBXb3JkIGRvY3VtZW50cy4gRm9yIG1vcmUgZGV0YWlscyBvbiB1c2luZyBSIE1hcmtkb3duIHNlZSA8aHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbT4uCgpXaGVuIHlvdSBjbGljayB0aGUgKipLbml0KiogYnV0dG9uIGEgZG9jdW1lbnQgd2lsbCBiZSBnZW5lcmF0ZWQgdGhhdCBpbmNsdWRlcyBib3RoIGNvbnRlbnQgYXMgd2VsbCBhcyB0aGUgb3V0cHV0IG9mIGFueSBlbWJlZGRlZCBSIGNvZGUgY2h1bmtzIHdpdGhpbiB0aGUgZG9jdW1lbnQuIFlvdSBjYW4gZW1iZWQgYW4gUiBjb2RlIGNodW5rIGxpa2UgdGhpczoKCmBgYHtyfQoKc3RvcCA8LSBmdW5jdGlvbigpewoKCmxpYnJhcnkoYXBlKQpsaWJyYXJ5KHBoeXRvb2xzKQpsaWJyYXJ5KGRpdmVyc2l0cmVlKQpsaWJyYXJ5KHNwZGVwKQpsaWJyYXJ5KFJjcHApCmxpYnJhcnkobXNtKQpsaWJyYXJ5KEZBUk0pCm9wdGlvbnMocmVwb3MgPSBjKENSQU4gPSAiaHR0cDovL2NyYW4ucnN0dWRpby5jb20iKSkKaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQpsaWJyYXJ5KGRldnRvb2xzKQppbnN0YWxsX2dpdGh1YigiQnJ1bm9WaWxlbGEvRkFSTSIpCmxpYnJhcnkoRkFSTSkKCmxvYWQoJ34vRG93bmxvYWRzL0ZVTExfVFJFRV9Tb2NpZXR5X2RhdGFfd2l0aF9iaW5hcnlfY29udmVyc2lvbnMuUmRhdGEnKQoKbG9hZCgnfi9Eb3dubG9hZHMvVHJlZV9GVUxMX3RyaW1tZWQuUmRhdGEnKQoKdGhpc190cmVlIDwtIGZ1bGxfdHJlZSAKCgpsb2FkKCd+L0Rvd25sb2Fkcy9kb3dubG9hZC5SZGF0YScpCm9iamVjdHMoKQpzdHIobXlPdXQpCgoKdGhpc193b3JsZCA8LSBteU91dCRteVdvcmxkCgojIyBUaGlzIG1vZHVsZSBhbmFseXplcyB0aGUgcmVzdWx0cyBmcm9tIG1vZHVsZSAxIGFuZCByZXR1cm5zIGEgbGlzdCBiYXNlZCBvbiBob3cgbWFueSB2YWx1ZXMgZWFjaCBzdGF0IHJldHVybnMKIyMgVHkgVHVmZiBhbmQgQnJ1bm8gVmlsZWxhCiMjIDI0IEF1Z3VzdCAyMDE2CgojIyMjIyMgU3BlY2lmeSBmdW5jdGlvbiAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCgoKICAgICMgIHRoaXNfdHJlZSA8LSBNb2R1bGVfMV9vdXRwdXQkbXl0cmVlCiAgICAjICB0aGlzX3dvcmxkIDwtIE1vZHVsZV8xX291dHB1dCRteVdvcmxkCgoKICAgICAgIyMjIyMgKDApIFB1bGwgbmVjZXNzYXJ5IHZhcmlhYmxlcyBmcm9tIHNpbXVsYXRlZCB0cmVlcyBhbmQgb3JnYW5pemUgaW50byBhIHNpbmdsZSBvYmplY3QgZm9yIGFsbCB0aGUgdGVzdHMgYmVsb3cgdG8gcHVsbCBmcm9tLgoKICAgICAgI3N0cihhbGxfdHJlZXMpCiAgICAgICNzdHIodGhpc190cmVlKQoKCiAgICAgICMjIDBhKSBCcmFuY2ggbGVuZ3RocwogICAgICBCcmFuY2hfTGVuZ3RocyA8LSB0aGlzX3RyZWUkZWRnZS5sZW5ndGgKICAgICAgbnVtYmVyX29mX2JyYW5jaGVzIDwtIGxlbmd0aChCcmFuY2hfTGVuZ3RocykKCiAgICAgICMgQW5jaG9yIHRlc3QgPSBQRCAoRmFpdGgncyBwaHlsb2dlbmV0aWMgZGl2ZXJzaXR5KQogICAgICBQeWxvX2RpdmVyc2l0eV9pc19zdW1fb2ZfQkwgPC0gc3VtKEJyYW5jaF9MZW5ndGhzKQoKICAgICAgIyBhdlBEIC0tIEF2ZXJhZ2UgcGh5bG9nZW5ldGljIGRpdmVyc2l0eQogICAgICBhdmVyYWdlX3BoeWxvZ2VuZXRpY19kaXZlcnNpdHlfaXNfbWVhbl9vZl9CTCA8LSBtZWFuKEJyYW5jaF9MZW5ndGhzKQoKICAgICAgdmFyaWFuY2VfUHlsb19kaXZlcnNpdHlfaXNfdmFyaWFuY2Vfb2ZfQkwgPC0gdmFyKEJyYW5jaF9MZW5ndGhzKQogICAgICBjYXQoIi0iKQogICAgICAjIyAwYikgUGFpcndpc2UgZGlzdGFuY2UgYmV0d2VlbiB0aXBzCiAgICAgIFBhaXJ3aXNlX2Rpc3QgPC0gY29waGVuZXRpYyh0aGlzX3RyZWUpCiAgICAgIGNhdCgiLSIpCiAgICAgICMgMmIpIFBhaXJ3aXNlIGRpc3RhbmNlIC0tIFN1bSBvZiBwYWlyd2lzZSBkaXN0YW5jZXMKCiAgICAgICMgRiAtLSBFeHRlbnNpdmUgcXVhZHJhdGljIGVudHJvcHkKICAgICAgRl9xdWFkcmF0aWNfZW50cm9weV9pc19zdW1fb2ZfUEQgPC0gc3VtKFBhaXJ3aXNlX2Rpc3QpCgogICAgICAjTWVhbiBpbnRlci1zcGVjaWVzIGRpc3RhbmNlcwoKICAgICAgIyBBbmNob3IgdGVzdCA9IE1QRCAobWVhbiBwYWlyd2lzZSBkaXN0YW5jZSkKCiAgICAgIE1lYW5fcGFpcndpc2VfZGlzdGFuY2UgPC0gbWVhbihQYWlyd2lzZV9kaXN0KQoKICAgICAgY2F0KCItIikKICAgICAgI1BhaXJ3aXNlIGRpc3RhbmNlL2FsbCBkaXN0YW5jZXMgLS0gVmFyaWFuY2Ugb2YgcGFpcndpc2UgZGlzdGFuY2VzCgogICAgICAjIEFuY2hvciB0ZXN0ID0gVlBEICh2YXJpYXRpb24gb2YgcGFpcndpc2UgZGlzdGFuY2UpCgogICAgICB2YXJpYW5jZV9wYWlyd2lzZV9kaXN0YW5jZSA8LSB2YXIoYXMudmVjdG9yKFBhaXJ3aXNlX2Rpc3QpKQoKCgoKICAgICAgIyMgMGMpIFBoeWxvZ2VuZXRpYyBpc29sYXRpb24KCiAgICAgICMgVXNpbmcgZXF1YWwuc3BsaXRzIG1ldGhvZCwgZmFzdGVyIGNvbXB1dGF0aW9uCiAgICAgIEV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3MgPC0gZXZvbC5kaXN0aW5jdDIodGhpc190cmVlLCB0eXBlID0gImVxdWFsLnNwbGl0cyIpCiAgICAgIGNhdCgiLSIpCiAgICAgICMgRUQgLSBTdW1tZWQgZXZvbHV0aW9uYXJ5IGRpc3RpbmN0aXZlbmVzcwoKICAgICAgRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzc19zdW0gPC0gc3VtKEV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3MpCgogICAgICAjIyAzZCkgUGh5bG9nZW5ldGljIGlzb2xhdGlvbiAtLSBNZWFuIG9mIHNwZWNpZXMgZXZvbHV0aW9uYXJ5IGRpc3RpbmN0aXZlbmVzcwoKICAgICAgIyBtZWFuKEVEKQoKICAgICAgbWVhbl9QaHlsb2dlbmV0aWNfaXNvbGF0aW9uIDwtIG1lYW4oRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzcykKCiAgICAgICMjIDRkKSBQaHlsb2dlbmV0aWMgaXNvbGF0aW9uIC0tIFZhcmlhbmNlIG9mIHNwZWNpZXMgaXNvbGF0aW9uIG1ldHJpY3MKCiAgICAgICN2YXIoRUQpCgogICAgICB2YXJpYW5jZV9QaHlsb2dlbmV0aWNfaXNvbGF0aW9uIDwtIHZhcihFdm9sdXRpb25hcnlfZGlzdGluY3RpdmVuZXNzKQogICAgICBjYXQoIi0iKQoKICAgICAgIyMgVHJlZSB0b3BvbG9neQoKICAgICAgI0dhbW1hIGluZGV4CgogICAgICBsdHRzIDwtIGx0dCh0aGlzX3RyZWUsIGdhbW1hID0gVFJVRSwgcGxvdCA9IEZBTFNFKQogICAgICBsaW5lYWdlc190aHJvdWdoX3RpbWUgPC0gYXMubnVtZXJpYyhsdHRzW1sxXV0pCiAgICAgIHRpbWVfc3RlcHMgPC0gYXMubnVtZXJpYyhsdHRzW1syXV0pCiAgICAgIGdhbW1hIDwtIGx0dHNbWzNdXQogICAgICBnYW1tYV9wX3ZhbHVlIDwtIGx0dHNbWzRdXQogICAgICBjYXQoIi0iKQoKICAgICAgIyMjIyMgKDUpIFRyZWUgbWV0cmljIC0tIE1hY3JvZXZvbHV0aW9uYXJ5IC0gUmF0ZSBhbmQgcmF0ZSBjaGFuZ2VzICMjIyMjIyMjIyMjIyMjIwogICAgICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKICAgICAgIyMgU3BlY2lhdGlvbiB2cyBleHRpbmN0aW9uIHJhdGVzIGFuZCBOZXQgZGl2ZXJzaWZpY2F0aW9uCiAgICAgIGJkcyA8LSBiZCh0aGlzX3RyZWUpCiAgICAgIHNwZWNpYXRpb25fcmF0ZSA8LSBiZHNbMV0KICAgICAgZXh0aW5jdGlvbl9yYXRlIDwtIGJkc1syXQogICAgICBleHRpbmN0aW9uX3Blcl9zcGVjaWF0aW9uIDwtIGJkc1szXQogICAgICBzcGVjaWF0aW9uX21pbnVzX2V4dGluY3Rpb24gPC0gYmRzWzRdCiAgICAgIGNhdCgiLSIpCgoKICAgICAgIyMgU3BlY2lhdGlvbiB2cyBleHRpbmN0aW9uIHJhdGVzIGFuZCBOZXQgZGl2ZXJzaWZpY2F0aW9uIGRlcGVuZGVudCBvbiB0cmFpdAogICAgICBOLmZvci5kb20gPC0gdGFibGUodGhpc193b3JsZFssIDZdKQogICAgICBpZihsZW5ndGgoTi5mb3IuZG9tKSA9PSAyKSB7CiAgICAgICAgcGFyLmRpdi5kZXAgPC0gRGl2RGVwKCBteXRyZWUgPSB0aGlzX3RyZWUsIG15V29ybGQgPSB0aGlzX3dvcmxkKQogICAgICAgIHRyYWl0XzFfc3BlY2lhdGlvbiA8LSBwYXIuZGl2LmRlcFsxXQogICAgICAgIHRyYWl0XzJfc3BlY2lhdGlvbiA8LSBwYXIuZGl2LmRlcFsyXQogICAgICAgIHRyYWl0XzFfZXh0aW5jdGlvbiA8LSBwYXIuZGl2LmRlcFszXQogICAgICAgIHRyYWl0XzJfZXh0aW5jdGlvbiA8LSBwYXIuZGl2LmRlcFs0XQogICAgICAgIHRyYW5zaXRpb25fZnJvbV90cmFpdF8xX3RvXzIgPC0gcGFyLmRpdi5kZXBbNV0KICAgICAgICB0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMl90b18xIDwtIHBhci5kaXYuZGVwWzZdCiAgICAgICAgdHJhbnNpdGlvbl9yYXRlX3JhdGlvXzF0bzJfb3Zlcl8ydG8xIDwtIHRyYW5zaXRpb25fZnJvbV90cmFpdF8xX3RvXzIvdHJhbnNpdGlvbl9mcm9tX3RyYWl0XzJfdG9fMQogICAgICAgIGNhdCgiLSIpCgoKICAgICAgICAjIyBDcm93biBhZ2UgcGVyIHRyYWl0IEFVQyBhbmQgZWZmZWN0IHNpemUKICAgICAgICB0aXAubGVuZ3RoIDwtIHRoaXNfdHJlZSRlZGdlLmxlbmd0aFt0aGlzX3RyZWUkZWRnZVssIDJdICVpbiUgMTpOdGlwKHRoaXNfdHJlZSldCiAgICAgICAgdGlwLmxlbmd0aCA8LSAodGlwLmxlbmd0aCAtIG1pbih0aXAubGVuZ3RoKSkgLyAobWF4KHRpcC5sZW5ndGgpIC0gbWluKHRpcC5sZW5ndGgpKQogICAgICAgIHRoaXNfdHJhaXQgPC0gdGhpc193b3JsZFttYXRjaCh0aGlzX3RyZWUkdGlwLmxhYmVsLCB0aGlzX3dvcmxkWywgOF0pLCA2XQogICAgICAgIHRpcC5sZW5ndGguMiA8LSB0aXAubGVuZ3RoW3RoaXNfdHJhaXQgPT0gMl0KICAgICAgICB0aXAubGVuZ3RoLjEgPC0gdGlwLmxlbmd0aFt0aGlzX3RyYWl0ID09IDFdCiAgICAgICAgbW9kZWwgPC0gZ2xtKGFzLmZhY3Rvcih0aGlzX3RyYWl0KSB+IGxvZyh0aXAubGVuZ3RoICsgMSksCiAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIpCiAgICAgICAgZWZmZWN0LnNpemUgPC0gbW9kZWwkY29lZmZpY2llbnRzWzJdCiAgICAgICAgcGxvdCh5ID0gdGhpc190cmFpdCAtIDEsIHg9IGxvZyh0aXAubGVuZ3RoKSkKICAgICAgICBwIDwtIHByZWRpY3QobW9kZWwsIGFzLmZhY3Rvcih0aGlzX3RyYWl0KSwgdHlwZSA9ICJyZXNwIikKICAgICAgICBwb2ludHMoeSA9IHAsIHggPSBsb2codGlwLmxlbmd0aCksIGNvbCA9ICJyZWQiKQogICAgICAgIHByIDwtIHByZWRpY3Rpb24ocCwgYXMuZmFjdG9yKHRoaXNfdHJhaXQpKQogICAgICAgIGF1Yy5tb2RlbCA8LSBwZXJmb3JtYW5jZShwciwgbWVhc3VyZSA9ICJhdWMiKUB5LnZhbHVlc1tbMV1dCgogICAgICAgICMjIFBoeWxvZ2VuZXRpYyBzaWduYWwgKEQpCiAgICAgICAgUGh5bG9nZW5ldGljX3NpZ25hbCA8LSBEc2lnKG15dHJlZSA9IHRoaXNfdHJlZSwgbXlXb3JsZCA9IHRoaXNfd29ybGQpCiAgICAgICAgY2F0KCItIikKCiAgICAgICAgIyMgU3BhdGlhbCBBbmFseXNpcwogICAgICAgIG5iczAgPC0ga25lYXJuZWlnaChhcy5tYXRyaXgodGhpc193b3JsZFssIDI6M10pLCBrID0gNywgbG9uZ2xhdCA9IFRSVUUpCiAgICAgICAgbmJzIDwtIGtubjJuYihuYnMwLCBzeW0gPSBUUlVFKSAjIDcgc3ltbWV0cmljIG5laWdoYm9ycwogICAgICAgIG5icy5saXN0dyA8LSBuYjJsaXN0dyhuYnMpCiAgICAgICAgZmFjdG9ycy5uYnMgPC0gYXMuZmFjdG9yKGlmZWxzZShpcy5uYSh0aGlzX3dvcmxkWywgNl0pLCAzLCB0aGlzX3dvcmxkWywgNl0pKQogICAgICAgIHNwYXRpYWwudGVzdHMgPC0gam9pbmNvdW50LnRlc3QoZnggPSBmYWN0b3JzLm5icywgbGlzdHcgPSBuYnMubGlzdHcpCiAgICAgICAgc3BhdGlhbC50ZXN0cy5mb3JhIDwtIHNwYXRpYWwudGVzdHNbWzFdXSRzdGF0aXN0aWMKICAgICAgICBzcGF0aWFsLnRlc3RzLmRvbSA8LSBzcGF0aWFsLnRlc3RzW1syXV0kc3RhdGlzdGljCiAgICAgICAgcHJldmFsZW5jZSA8LSAoTi5mb3IuZG9tWzFdIC0gTi5mb3IuZG9tWzJdKSAvIHN1bShOLmZvci5kb20pCiAgICAgICAgY2F0KCItIikKICAgICAgfSBlbHNlIHsKICAgICAgICB0cmFpdF8xX3NwZWNpYXRpb24gPC0gTkEKICAgICAgICB0cmFpdF8yX3NwZWNpYXRpb24gPC0gTkEKICAgICAgICB0cmFpdF8xX2V4dGluY3Rpb24gPC0gTkEKICAgICAgICB0cmFpdF8yX2V4dGluY3Rpb24gPC0gTkEKICAgICAgICB0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMV90b18yIDwtIE5BCiAgICAgICAgdHJhbnNpdGlvbl9mcm9tX3RyYWl0XzJfdG9fMSA8LSBOQQogICAgICAgIHRyYW5zaXRpb25fcmF0ZV9yYXRpb18xdG8yX292ZXJfMnRvMSA8LSBOQQogICAgICAgIFBoeWxvZ2VuZXRpY19zaWduYWwgPC0gTkEKICAgICAgICBzcGF0aWFsLnRlc3RzLmZvcmEgPC0gTkEKICAgICAgICBzcGF0aWFsLnRlc3RzLmRvbSA8LSBOQQogICAgICAgIGF1Yy5tb2RlbCA8LSBOQQogICAgICAgIGVmZmVjdC5zaXplIDwtIE5BCiAgICAgICAgcHJldmFsZW5jZSA8LSBpZmVsc2UobmFtZXModGFibGUodGhpc193b3JsZFssIDZdKVsxXSkgPT0gIjEiLCAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0xKQogICAgICAgIGNhdCgiLS0tIikKCiAgICAgIH0KCgoKCiAgICAgIHJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMSA8LSBjYmluZCgKCiAgICAgICAgbnVtYmVyX29mX2JyYW5jaGVzLAogICAgICAgIFB5bG9fZGl2ZXJzaXR5X2lzX3N1bV9vZl9CTCwKICAgICAgICBhdmVyYWdlX3BoeWxvZ2VuZXRpY19kaXZlcnNpdHlfaXNfbWVhbl9vZl9CTCwKICAgICAgICB2YXJpYW5jZV9QeWxvX2RpdmVyc2l0eV9pc192YXJpYW5jZV9vZl9CTCwKCiAgICAgICAgRl9xdWFkcmF0aWNfZW50cm9weV9pc19zdW1fb2ZfUEQsCiAgICAgICAgTWVhbl9wYWlyd2lzZV9kaXN0YW5jZSwKICAgICAgICB2YXJpYW5jZV9wYWlyd2lzZV9kaXN0YW5jZSwKCiAgICAgICAgRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzc19zdW0sCiAgICAgICAgbWVhbl9QaHlsb2dlbmV0aWNfaXNvbGF0aW9uLAogICAgICAgIHZhcmlhbmNlX1BoeWxvZ2VuZXRpY19pc29sYXRpb24sCgogICAgICAgIGdhbW1hLAogICAgICAgIGdhbW1hX3BfdmFsdWUsCiAgICAgICAgc3BlY2lhdGlvbl9yYXRlLAogICAgICAgIGV4dGluY3Rpb25fcmF0ZSwKICAgICAgICBleHRpbmN0aW9uX3Blcl9zcGVjaWF0aW9uLAogICAgICAgIHNwZWNpYXRpb25fbWludXNfZXh0aW5jdGlvbiwKICAgICAgICB0cmFpdF8xX3NwZWNpYXRpb24sCiAgICAgICAgdHJhaXRfMl9zcGVjaWF0aW9uICwKICAgICAgICB0cmFpdF8xX2V4dGluY3Rpb24gLAogICAgICAgIHRyYWl0XzJfZXh0aW5jdGlvbiAsCiAgICAgICAgdHJhbnNpdGlvbl9mcm9tX3RyYWl0XzFfdG9fMiAsCiAgICAgICAgdHJhbnNpdGlvbl9mcm9tX3RyYWl0XzJfdG9fMSAsCiAgICAgICAgdHJhbnNpdGlvbl9yYXRlX3JhdGlvXzF0bzJfb3Zlcl8ydG8xICwKICAgICAgICBQaHlsb2dlbmV0aWNfc2lnbmFsLAogICAgICAgIHNwYXRpYWwudGVzdHMuZm9yYSwKICAgICAgICBzcGF0aWFsLnRlc3RzLmRvbSwKICAgICAgICBwcmV2YWxlbmNlLAogICAgICAgIGF1Yy5tb2RlbCwKICAgICAgICBlZmZlY3Quc2l6ZQogICAgICApCiAgICAgIHJvd25hbWVzKHJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMSkgPC0gMQoKICAgICAgcmVzdWx0c19zdW1tYXJ5X21hdHJpeF8yIDwtIGNiaW5kKAogICAgICAgIGMoRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzcyxOQSksCiAgICAgICAgbGluZWFnZXNfdGhyb3VnaF90aW1lLAogICAgICAgIHRpbWVfc3RlcHMKICAgICAgKQogICAgICBjb2xuYW1lcyhyZXN1bHRzX3N1bW1hcnlfbWF0cml4XzIpIDwtIGMoIkV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3MiLCAibGluZWFnZXNfdGhyb3VnaF90aW1lIiwgInRpbWVfc3RlcHMiKQogICAgICMgaGVhZChyZXN1bHRzX3N1bW1hcnlfbWF0cml4XzIpCgogICAgICAjIyMgUmV0dXJucyBmcm9tIGZ1bmN0aW9uIGluIGxpc3QgZm9ybQogICAgICByZXR1cm5zIDwtIGxpc3QoCiAgICAgICAgI0JyYW5jaF9MZW5ndGhzLAogICAgICAgICNQYWlyd2lzZV9kaXN0LAogICAgICAgIHJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMSwKICAgICAgICByZXN1bHRzX3N1bW1hcnlfbWF0cml4XzIKCiAgICAgICkKCiAgICAgIG5hbWVzKHJldHVybnMpIDwtIGMoCiAgICAgICAgIyJCcmFuY2hfTGVuZ3RocyIsCiAgICAgICAgIyJQYWlyd2lzZV9kaXN0YW5jZSIsCiAgICAgICAgInJlc3VsdHNfc3VtbWFyeV9vZl9zaW5nbGVfdmFsdWVfb3V0cHV0cyIsCiAgICAgICAgInJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfb2ZfbXVsdGlfdmFsdWVfb3V0cHV0cyIKICAgICAgKQogICAgICBjYXQoIl0gMTAwJSIpCgogICAgICAKCiAgICB9CiAgCgoKI01vZHVsZV8yKG15T3V0KQoKYGBgCgojIyBJbmNsdWRpbmcgUGxvdHMKCllvdSBjYW4gYWxzbyBlbWJlZCBwbG90cywgZm9yIGV4YW1wbGU6CgpgYGB7ciBwcmVzc3VyZSwgZWNobz1GQUxTRX0KcGxvdChwcmVzc3VyZSkKYGBgCgpOb3RlIHRoYXQgdGhlIGBlY2hvID0gRkFMU0VgIHBhcmFtZXRlciB3YXMgYWRkZWQgdG8gdGhlIGNvZGUgY2h1bmsgdG8gcHJldmVudCBwcmludGluZyBvZiB0aGUgUiBjb2RlIHRoYXQgZ2VuZXJhdGVkIHRoZSBwbG90LgoKPCEtLWNoYXB0ZXI6ZW5kOlRyZWVfYW5kX3NwYWNlX2FuYWx5c2lzX2Z1bmN0aW9uLlJtZC0tPgoKLS0tCnRpdGxlOiAiRC1wbGFjZSBGQVJNIGRvY3VtZW50YXRpb24iCmF1dGhvcjogIlR5IFR1ZmYsIEJydW5vIFZpbGVsYSwgYW5kIENhcmxvcyBCb3Rlcm8iCmRhdGU6ICdwcm9qZWN0IGJlZ2FuOiAxNSBNYXkgMjAxNiwgZG9jdW1lbnQgdXBkYXRlZDogYHIgc3RyZnRpbWUoU3lzLnRpbWUoKSwgZm9ybWF0CiAgPSAiJWQgJUIgJVkiKWAnCmJpYmxpb2dyYXBoeTogRkFSTSBwYWNrYWdlLmJpYiAgCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKCi0tLQoKQE5pZWxzZW4KCiMgTW9kdWxlIDI6IFNwYWNlIGFuZCBwaHlsb2dlbnkgc3VtbWFyeSBzdGF0aXN0aWNzIAogIFRoaXMgaXMgdGhlIG1hc3RlciBkb2N1bWVudCBmb3IgTW9kdWxlIDIsIGEgZm91bmRhdGlvbmFsIGZ1bmN0aW9uIGluIG91ciBGQVJNIHBhY2thZ2UgdGhhdCBhbmFseXplcyByZXN1bHRzIGZyb20gTW9kdWxlIDEsIHRoZSBvdGhlciBmb3VuZGF0aW9uYWwgZnVuY3Rpb24uIE1vZHVsZSAxIHNpbXVsYXRlcyBhIHNwYXRpYWwgcGF0dGVybiBhbmQgYSBwaHlsb2dlbmV0aWMgdHJlZSBnaXZlbiBhIHNldCBvZiBlbnZpcm9ubWVudGFsIGFuZCBpbmhlcml0YW5jZSBydWxlcyBhbmQgdGhlbiBNb2R1bGUgMiBzdW1tYXJpemVzIHRob3NlIHNpbXVsYXRlZCByZXN1bHRzIHVzaW5nIGEgbGFyZ2Ugc2V0IG9mIHRhcmdldGVkIHN1bW1hcnkgc3RhdGlzdGljcy4gSGVyZSB3ZSBkZXNjcmliZSBvdXIgY2hvaWNlIG9mIHN1bW1hcnkgc3RhdGlzdGljcywganVzdGlmeSB0aG9zZSBjaG9pY2VzIGFzIHBhcnQgb2YgYSBsYXJnZXIgdGhlb3JldGljYWwgY29udGV4dCwgYW5kIHByb3ZpZGUgb3VyIHJlcHJvZHVjYWJsZSBjb2RlIGZvciBleGVjdXRpbmcgdGhlIGFuYXlsc2VzIHlvdXJzZWxmLiBUaGVzZSB0d28gcGFydHMgYXJlIHNlcGVyYXRlZCBpbnRvIG1vZHVsZXMgc28gdGhhdCB0aGV5IGNhbiBhY3QgaW5kZXBlbmRlbnRseS4gQW4gY29tYmluYXRpb24gb2Ygc3BhdGlhbCBwYXR0ZXJuIGFuZCBhc3NvY2lhdGVkIHBoeWxvZ2VueSBtYW55IGJlIHVzZWQgYXMgbG9uZyBhcyB0aGV5IGFyZSBmb3JtYXR0ZWQgY29ycmVjdGx5LiAgICAgICAgIAoKVGhpcyBwaXBlbGluZSB3YXMgZGVzaWduZWQgdG8gYW5hbHl6ZSBhIHNpbXVsYXRlZCB3b3JsZCB3aGVyZSBhbGwgdGhlIGluZm9ybWF0aW9uIGlzIGtub3duIGFib3V0IGJvdGggdGhlIHdvcmxkIGFuZCB0aGUgdHJlZS4gVGhlcmUgaXMgbm8gbWlzc2luZyBpbmZvcm1hdGlvbiwganVzdCBleHRpbmN0IHRyZWVzLiBUaGlzIGlzIG11Y2ggZGlmZmVyZW50IHRoYW4gb3VyIHJlYWwgdHJlZSB0aGF0IGhhcyBsb2FkcyBvZiB1bmNlcnRhaW50eSB1bmV2ZW5seSBkZXN0cmlidXRlZCBhY3Jvc3MgaXQuIFRoZSByZXN1bHQgeW91IHNlZSBkZW1vbnN0cmF0ZWQgcmlnaHQgbm93IGFyZSBvbmUgc2ltdWxhdGVkIHJlc3VsdCBvZiBtYW55LiBJIG5lZWQgdG8gZG8gYSBzaXN0ZXIgcGFnZSB0byB0aGlzIHdlcmUgd2UgZG8gdGhpcyBlbnRpcmUgYW5hbHlzaXMgb24gdGhlIHJlYWwgdHJlZSwgb3IgYmVzdCByZWFsIHRyZWUgd2UndmUgZ290LiAKCldlIGhhdmUgZm91ciB0eXBlcyBvZiBkYXRhIGF2YWlsYWJsZSBmb3IgYXNraW5nIHJlc2VhcmNoIHF1ZXN0aW9ucyB1c2luZyBELXBsYWNlIGRhdGE6IFtwaHlsb2dlbmllc10oI3BoeWxvZ2VuZXRpYy1zdW1tYXJ5LXN0YXRpc3RpY3MpLCBbc3BhdGlhbCBsb2NhdGlvbnNdKCNzcGF0aWFsLWxvY2F0aW9ucyksIHRyYWl0IGlkZW50aXRpZXMsIGFuZCBlbnZpcm9ubWVudGFsIHJlY29uc3RydWN0aW9ucy4gQW55IG9uZSBvZiB0aGVzZSBmb3VyIGRhdGEgdHlwZXMgYWxvbmUgYXJlIHJlbGF0aXZlbHkgaW5mb3JtYXRpb24gcG9vciwgc28gd2UgYXJlIHNlYXJjaGluZyBmb3Igd2F5cyB0byBtb2RlbCBjb25uZWN0aW9ucyBiZXR3ZWVuIHRoZXNlIGRhdGEgdHlwZXMgdG8gZHJhdyBzdHJvbmdlciBjb25jbHVzaW9ucyBvdmVyYWxsLiAKCk90aGVyIG1vZHVsZXMgY2FuIHVzZSB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzIGdlbmVyYXRlZCBmcm9tIHRoaXMgbW9kdWxlIHRvIHRlc3QgaHlwb3RoZXNlcy4gV2UgY3VycmVudGx5IGhhdmUgYSBBQkMgYW5kIFJhbmRvbSBGb3Jlc3QgbW9kdWxlIHN0YXJ0ZWQgYnV0IHRoZXJlIHdpbGwgYmUgbW9yZSB0byBjb21lLiAKClRoZXNlIGFyZSBxdWFudGl0YXRpdmUgY29ubmVjdGlvbnMgdGhhdCB3ZSBhcmUgYXNzdW1lZCBpbiB0aGUgYW5hbHlzZXMsIGJ1dCB3ZSBkb24ndCBhY3R1YWxseSBoYXZlIGFueSBzdXBwb3J0IGluIHRoZSBkYXRhIGZvciBkb2luZyBzby4gCjEuIG5lYXJlc3QgbmVpZ2hib3IgY29ubmVjdGl2aXR5IG1lYXN1cmVzCjIuIEFidW5kYW5jZSBlc3RpbWF0ZXMKMy4gUGFpcndpc2UgaW5mbHVlbmNlIChoaXN0b3J5KSBiZXR3ZWVuIGN1bHR1cmVzLiAKNC4gRW52aXJvbm1lbnRhbCByZWNvbnN0cnVjdGlvbiB2YWxpZGF0aW9uIGV2aWRlbmNlIAoKIyBQaHlsb2dlbmV0aWMgc3VtbWFyeSBzdGF0aXN0aWNzICAKCldob2xlIHRyZWUgdnMuIHBhcnQgb2YgdHJlZT8gVGhlc2Ugc3RhdGlzdGljcyBhcmUgZ2VuZXJhbGx5IHVzZWQgdG8gY29tcGFyZSBvbmUgc2FtcGxlIHRvIGFub3RoZXIuIEZvciBleGFtcGxlLCBhbiBleHBlcmltZW50YWwgY29udHJhc3QgYmV0d2VlbiB0d28gc2l0ZXMsIHR3byBwaHlsb2dlbmV0aWMgZ3JvdXBzLCBvciB0d28gY29tbXVuaXRpZXMgaW4gdHdvIGRpZmZlcmVudCBsb2NhdGlvbnMuIEhlcmUgd2UgYXJlIGNhbGN1bGF0aW5nIHRoZXNlIHN0YXRpc3RpY3MgZm9yIHRoZSBnbG9iYWwgbGFuZ2F1YWdlIHRyZWUgdG8gY29tcGFyZSBhZ2FpbnN0IGdsb2JhbCB0cmVlcyBjcmVhdGVkIGluIG91ciBzaW11bGF0aW9uLiBZb3Ugc3RpbGwgcmV0YWluIHRoZSBhYmlsaXR5IHRvIHN1YnNldCB0aGlzIHRyZWUgb3Igb3RoZXJzIGFuZCBzZW5kIG9ubHkgdGhvc2Ugc3Vic2V0cyB0aHJvdWdoIHRoaXMgY29kZSB0byBjb21wYXJlIHRoZSB2YWx1ZXMgd2l0aCBlYWNoIG90aGVyIGFmdGVyd2FyZHMuIAoKKiBJbnRyb2R1Y3Rpb24gYW5kIGZyYW1ld29yawoqIFtBbHBoYSBEaXZlcnNpdHkgbWV0cmljc10oI2FscGhhLWRpdmVyc2l0eS1tZXRyaWNzKSAKICAxLiBbQnJhbmNoIExlbmd0aCAocmljaG5lc3MgYW5kIGRpdmVyZ2VuY2UpXSgjYnJhbmNoLWxlbmd0aHMpCiAgMi4gW1BhaXJ3aXNlIGRpc3RhbmNlIGJldHdlZW4gdGlwcyAocmljaG5lc3MsIGRpdmVyZ2VuY2UsIGFuZCByZWd1bGFyaXR5KV0oI3BhaXJ3aXNlLWRpc3RhbmNlLWJldHdlZW4tdGlwcykKICAzLiBbUGh5bG9nZW5ldGljIGlzb2xhdGlvbiAoZGl2ZXJnZW5jZSwgYW5kIHJlZ3VsYXJpdHkpXSgjcGh5bG9nZW5ldGljLWlzb2xhdGlvbikKICA0LiBbTmVhcmVzdCBOZWlnaGJvciAoZGl2ZXJnZW5jZSwgYW5kIHJlZ3VsYXJpdHkpXSgjbmVhcmVzdC1waHlsb2dlbmV0aWMtbmVpZ2hib3IpIAoqIFtCZXRhIERpdmVyc2l0eV0oI2JldGEtZGl2ZXJzaXR5KQoqIFtUcmVlIHRvcG9sb2d5XSgjdHJlZS10b3BvbG9neSkKKiBbTWFjcm9ldm9sdXRpb25hcnkgcmF0ZXNdKCNtYWNyb2V2b2x1dGlvbmFyeS1yYXRlcykKCgpBbGwgdHJlZXMgYXJlIHVsdHJhbWV0cmljLgoKCgojIyBJbnRyb2R1Y3Rpb24gYW5kIGZyYW1ld29yawoKCiAgVGhlIGNob2ljZSBvZiBwaHlsb2dlbmV0aWMgYW5hbHlzZXMgYW5kIG9yZ2FuaXphdGlvbmFsIHNjaGVtZSBpcyBiYXNlZCBvbiB0aGUgc3VnZ2VzdGlvbnMgb2YgVHVja2VyIGV0IGFsLiAyMDE2LiBIZXJlIGFyZSBhIGZldyBpbWFnZXMgZnJvbSB0aGF0IHBhcGVyIGZvciBhbiBvdmVydmlldzogIAoKCiFbRnJvbSBUdWNrZXIgZXQgYWwuIDIwMTYuIEJpb2xvZ2ljYWwgUmV2aWV3c10oSW1hZ2VzL1R1Y2tlcl8yMDE2L3RyZWVfY29uY2VwdC5qcGcpCiFbRnJvbSBUdWNrZXIgZXQgYWwuIDIwMTYuIEJpb2xvZ2ljYWwgUmV2aWV3c10oSW1hZ2VzL1R1Y2tlcl8yMDE2L2FscGhhX1BDQS5qcGcpCgohW0Zyb20gVHVja2VyIGV0IGFsLiAyMDE2LiBCaW9sb2dpY2FsIFJldmlld3NdKEltYWdlcy9UdWNrZXJfMjAxNi9UaHJlZV90eXBlX3N1bW1hcnkuanBnKQoKCiFbRnJvbSBUdWNrZXIgZXQgYWwuIDIwMTYuIEJpb2xvZ2ljYWwgUmV2aWV3c10oSW1hZ2VzL1R1Y2tlcl8yMDE2L3R1dG9yaWFsLmpwZykKCmBgYHtyfQojbG9hZCgnfi9Eb3dubG9hZHMvRlVMTF9UUkVFX1NvY2lldHlfZGF0YV93aXRoX2JpbmFyeV9jb252ZXJzaW9ucy5SZGF0YScpCgpsb2FkKCd+L0Rvd25sb2Fkcy9UcmVlX0ZVTExfdHJpbW1lZC5SZGF0YScpCgp0aGlzX3RyZWUgPC0gZnVsbF90cmVlIAoKCmxvYWQoJ34vRG93bmxvYWRzL2Rvd25sb2FkLlJkYXRhJykKCiNzdHIobXlPdXQpCgp0aGlzX3RyZWUgPC0gbXlPdXQkbXl0cmVlCnRoaXNfd29ybGQgPC0gbXlPdXQkbXlXb3JsZAoKI3N0cih0aGlzX3dvcmxkKQogICNzdHIoYWxsX3RyZWVzKQogICNzdHIodGhpc190cmVlKQoKCiNsaWJyYXJ5KGtuaXRyKQoja2FibGUodGhpc193b3JsZCwgY2FwdGlvbj0gIlRoaXMgaXMgb3VyIHdvcmxkIikKYGBgCgoKIyNBbHBoYSBkaXZlcnNpdHkgbWV0cmljcwoKIyMjIEJyYW5jaCBMZW5ndGhzCiAgQnJhbmNoIGxlbmd0aCBkYXRhIGlzIGVtYmVkZGVkIGluIHRoZSB0cmVlIG9iamVjdCBwcm92aWRlZCB0byB0aGlzIGZ1bmN0aW9uLiBUaGUgZmlyc3Qgc3RlcCBpbiBzdW1tYXJpemluZyB0aGUgbGVuZ3RocyBpcyB0byBleHRyYWN0IHRob3NlIGRhdGEgZnJvbSB0aGUgdHJlZSBvYmplY3QuIFRoZXNlIGRhdGEgYXJlIGNhbGxlZCAnZWRnZXMnIGluIHRoZSB0cmVlIG9iamVjdC4gV2UgZXh0cmFjdCBicmFuY2ggbGVuZ3RocyBhbmQgY3JlYXRlIGFuIG9iamVjdCBjYWxsZWQgJ0JyYW5jaF9sZW5ndGhzJyBmb3IgcGFzc2luZyBvbiB0byB0aGUgb3RoZXIgc3VtbWFyeSBmdW5jdGlvbnMuIFRoZSBoaXN0b2dyYW0gYmVsb3cgc2hvd3MgdGhlIGZyZXF1ZW5jeSBvZiBkaWZmZXJlbnQgYnJhbmNoIGxlbmd0aHMgZm91bmQgdGhyb3VnaG91dCB0aGUgdHJlZS4gCiAgCmBgYHtyfQogICAgICBCcmFuY2hfTGVuZ3RocyA8LSB0aGlzX3RyZWUkZWRnZS5sZW5ndGgKYGBgCgpgYGB7ciwgZWNobz1GQUxTRX0KICMgcGxvdCB0aGUgYnJhbmNoIGxlbmd0aHMKICAgICAgaGlzdChCcmFuY2hfTGVuZ3RocywgeGxhYj0iQnJhbmNoIExlbmd0aHMiLCBtYWluPSIiLCBicmVha3M9MTAwMCwgYm9yZGVyPU5BLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9MC45KSkKYGBgCldlIGNhbiBzdW1tYXJpemUgYnJhbmNoIGxlbmd0aHMgYWNjb3JkaW5nIHRvIG5vcm1hbCBzdW1tYXJ5IHN0YXRpc3RpY3MsIGJ1dCBpdCBjYW4gYmUgZGlmZmljdWx0IHRvIGFzc2lnbiBldm9sdXRpb25hcnkgbWVhbmluZyB0byBzb21lIG9mIHRoZXNlIG1ldHJpY3MgYW5kIHNvIHRoZXkgYXJlIG5vdCByZWd1bGFybHkgdXNlZCBhcyBiZXN0IEkgY2FuIHRlbGwuIFRoaXMgbGFjayBvZiBtZWFuaW5nIGRvZXMgbm90IG1lYW4gdGhhdCB0aGVzZSBzdGF0aXN0aWNzIGNvdWxkbid0IGJlIHVzZWQgdG8gZGlzdGluZ3Vpc2ggYmV0d2VlbiBsYXJnZSBzaW11bGF0ZWQgdHJlZXMuIApgYGB7cn0KICAgICAgbWVhbl9icmFuY2hfbGVuZ3RoIDwtIG1lYW4oQnJhbmNoX0xlbmd0aHMpCiAgICAgIHZhcmlhbmNlX2JyYW5jaF9sZW5ndGggPC0gdmFyKEJyYW5jaF9MZW5ndGhzKQogICAgICBTRF9icmFuY2hfbGVuZ3RoIDwtIHNkKEJyYW5jaF9MZW5ndGhzKQpgYGAKCgpgYGB7ciwgZWNobz1GQUxTRX0KcGFzdGUoIm1lYW4gYnJhbmNoIGxlbmd0aCA9ICIsIG1lYW5fYnJhbmNoX2xlbmd0aCkKcGFzdGUoInZhcmlhbmNlIGluIGJyYW5jaCBsZW5ndGhzID0gIiwgdmFyaWFuY2VfYnJhbmNoX2xlbmd0aCkKcGFzdGUoInN0YW5kYXJkIGRldmlhdGlvbiBpbiBicmFuY2ggbGVuZ3RocyA9ICIsIFNEX2JyYW5jaF9sZW5ndGgpCgpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQpwYXIobWFyPWMoMiw0LDAsMCkpCmJveHBsb3QoQnJhbmNoX0xlbmd0aHMsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0wLjUpLCBib3JkZXI9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9MSksIHlsYWI9IkJyYW5jaCBMZW5ndGhzIikKYGBgCgojIyMjIFBoeWxvZ2VuZXRpYyBkaXZlcnNpdHkgKCRQRCQpClBoeWxvZ2VuZXRpYyBkaXZlcnNpdHkgKCRQRCQpIGlzIHRoZSBzdW1tYXRpb24gKCRcc3VtJCkgb2YgYWxsIGJyYW5jaCBsZW5ndGhzIGNvbm5lY3Rpbmcgc3BlY2llcyB0b2dldGhlciwgd2hlcmUgJEJfe3R9JCBpcyB0aGUgc2V0IG9mIGluY2x1ZGVkIHRpcHMgYW5kICRMX3tifSQgaXMgQnJhbmNoIGxlbmd0aHMuIChGYWl0aCAxOTkyKSBUaGlzIGlzIGFuIGFuY2hvciB0ZXN0LCB3aGljaCBtZWFucyBpdCBpcyByZWd1bGFybHkgdXNlZCwgd2VsbCB1bmRlcnN0b29kLCBhbmQgd2Ugc2hvdWxkIHVzZSBpdCB0byBhbmNob3Igb3VyIHdvcmsgdG8gcGFzdCB3b3JrLiBQRCBpcyBhIHJpY2huZXNzIG1lYXN1cmUsIGl0IHRlbGxzIHVzIGhvdyBtdWNoIGV2b2x1dGlvbmFyeSBoaXN0b3J5IGlzIGFzc29jaWF0ZWQgd2l0aCBhIHNldCBvZiB0aXBzLiAgCgokJFBEID0gXHN1bV97YiBcaW4gQl97dH19Xnt9TF97Yn0kJAogCmBgYHtyfQoKIyBBbmNob3IgdGVzdCA9IFBEIChGYWl0aCdzIHBoeWxvZ2VuZXRpYyBkaXZlcnNpdHkpCiAgICAgIFB5bG9fZGl2ZXJzaXR5X2lzX3N1bV9vZl9CTCA8LSBzdW0oQnJhbmNoX0xlbmd0aHMpCiAgICAgIFB5bG9fZGl2ZXJzaXR5X2lzX3N1bV9vZl9CTApgYGAKCgogVGhlcmUgYXJlIHZhcmlhdGlvbnMgb24gdGhpcyBtZWFzdXJlIHRoYXQgd2UgaGF2ZSBOT1QgaW1wbGVtZW50ZWQgaGVyZS4gSXQgaXMgcG9wdWxhciB0byBzY2FsZSB0aGlzIG1lYXN1cmUgYWNjb3JkaW5nIHRvIHNvbWUgZWNvbG9naWNhbCBkcml2ZXIuIEJhcmtlciAoMjAwMikgc2NhbGVzIGJyYW5jaCBsZW5ndGhzICgkTF97Yn0kKSBieSBtdWx0aXBseWluZyB0aGVtIGFnYWluc3QgdGhlIGFidW5kYW5jZSBvZiBpbmRpdmlkdWFscyBhdCBhdCB0aXAgKCRBX3tifSQpLiBPdGhlcnMgKFJvc2F1ZXIgZXQgYWwuIDIwMDkpLCBzY2FsZSB0aGVtIGJ5IHRoZWlyIHJhbmdlIHNpemUgaW5zdGVhZCAoJFJfe2J9JCkuIAogCiAkJFxEZWx0YSBuIFBEID0gXHN1bV97YiBcaW4gQl97dH19Xnt9QV97Yn1MX3tifSQkCiQkUEUgPSBcc3VtX3tiIFxpbiBCX3t0fX1ee31cZGZyYWN7TF97Yn19e1Jfe2J9fSQkCkFyZ3VlaW5nIHRoYXQgcHJvcG9ydGlvbmFsIGFidW5kYW5jZSBwaHlsb2dlbmV0aWMgZGl2ZXJzaXR5ICgkUERfe0FifSQpIGlzIG1vcmUgZWZmZWN0aXZlIHRoYW4gdGhlIHN0YW5kYXJkIFBEIGNhbGN1bGF0ZWQgZnJvbSByYXcgYWJ1bmRhbmNlLCBWZWxsZW5kIGV0IGFsLiBwZW5uZWQgYSBuZXcgdmVyc2lvbiBvZiBQRCB3aGVyZSAkQiQgaXMgdGhlIHRvdGFsIG51bWJlciBvZiBicmFuY2ggbGVuZ3RocyAoJExfe2J9JCkuIE5vdGU6IFdlIGRvbid0IGhhdmUgYWJ1bmRhbmNlIGRhdGEgcmlnaHQgbm93IGZvciB0aGUgaHVtYW4gcHJvamVjdCBzbyB0aGlzIG1ldHJpYyBpcyBub3QgY3VycmVudGx5IHZlcnkgaGVscGZ1bC4gICAKJCRQRF97QWJ9ID0gQiAqIFxkZnJhY3tcc3VtX3tiIFxpbiBCX3t0fX1ee31BX3tifUxfe2J9fXtcc3VtX3tiIFxpbiBCX3t0fX1ee31BX3tifX0kJAoKYGBge3J9CiAgICAgICNDYWxjdWxhdGUgQgogICAgICBudW1iZXJfb2ZfYnJhbmNoZXMgPC0gbGVuZ3RoKEJyYW5jaF9MZW5ndGhzKQogICAgICBudW1iZXJfb2ZfYnJhbmNoZXMKYGBgCgojIyMjIEF2ZXJhZ2UgcGh5bG9nZW5ldGljIGRpdmVyc2l0eSAoJGF2UEQkKQpBdmVyYWdlIHBoeWxvZ2VuZXRpYyBkaXZlcnNpdHkgKCRhdlBEJCkgKGludHJvZHVjZWQgYnkgQ2xhcmtlIGFuZCBXYXJ3aWNrIDIwMDEpIGlzIGEgYnJhbmNoIGxlbmd0aC1iYXNlZCBkaXZlcmdlbmNlIGluZGljZXMgd2hlcmUgUEQgaXMgZGl2aWRlZCBieSB0aGUgdG90YWwgbnVtYmVyIG9mIHRpcHMgKCRTJCkgaW4gdGhlIHRyZWUuIAokJGF2UEQgPSBcZGZyYWN7UER9e1N9JCQKYGBge3J9CiAgICAgIE51bWJlcl9vZl90aXBzIDwtIGxlbmd0aCh0aGlzX3RyZWUkdGlwLmxhYmVsKQogICAgICBhdmVyYWdlX3BoeWxvZ2VuZXRpY19kaXZlcnNpdHkgPC0gUHlsb19kaXZlcnNpdHlfaXNfc3VtX29mX0JMIC8gTnVtYmVyX29mX3RpcHMKICAgICAgYXZlcmFnZV9waHlsb2dlbmV0aWNfZGl2ZXJzaXR5CmBgYAoKClRoZXJlIGlzIGFsc28gYSBwcm9wb3J0aW9uYWwgYWJ1bmRhbmNlIHZlcnNpb24gb2YgYXZlcmFnZSBwaHlsb2dlbmV0aWMgZGl2ZXJzaXR5ICgkYXZQRF97QWJ9JCkgKFR1Y2tlciBldCBhbC4gMjAxNikuIEFnYWluLCB3ZSBkb24ndCBoYXZlIGFidW5kYW5jZSB2YWx1ZXMgeWV0IGZvciBELXBsYWNlLiAKJCRhdlBEX3tBYn0gPSBcZGZyYWN7QiAqIFxkZnJhY3tcc3VtX3tiIFxpbiBCX3t0fX1ee31BX3tifUxfe2J9fXtcc3VtX3tiIFxpbiBCX3t0fX1ee31BX3tifX19e1N9JCQKCgojIyMgUGFpcndpc2UgZGlzdGFuY2UgYmV0d2VlbiB0aXBzCgpUaGlzIGlzIHRoZSBwYXRyaXN0aWMgZGlzdGFuY2UsIHRoZSBzdW0gb2YgdGhlIGJyYW5jaCBsZW5ndGhzIGZvbGxvd2luZyB0aGUgc2hvcnRlc3QgZGlzdGFuY2UgYmV0d2VlbiB0d28gdGlwcyBpbiBhIHRyZWUsIGltcGxlbWVudGVkIGFzIGEgZGlzdGFuY2UgbWF0cml4IHdoZXJlIGV2ZXJ5IHRpcCBpcyBjb21wYXJlZCB0byBldmVyeSBvdGhlciB0aXAuIFRoaXMgZGlzdGFuY2UgZnVuY3Rpb24gY2FuIGJlIGFueXRoaW5nLiBXZSB1c2UgZXVjbGlkZWFuIGFuZCBlbnZpcm9ubWVudGFsIGRpc3RhbmNlIG1hdHJpY2VzIGhlYXZpbHkgaW4gdGhlIHNwYXRpYWwgYW5hbHlzZXMuIAoKIyMjIyBDYWxjdWxhdGUgdGhlIHBhdHJpc3RpYyBkaXN0YW5jZSBiZXR3ZWVuIHR3byB0YXhhLCBmb3IgYWxsIHRheGEKQ2FsY3VsYXRlIHRoZSBwYXRyaXN0aWMgZGlzdGFuY2UgYmV0d2VlbiB0d28gdGF4YSB1c2luZyB0aGUgUiBwYWNrYWdlICdwaHl0b29scycsIHRoaXMgZnVuY3Rpb24gdGFrZXMgYSAncGh5bG8nIHRyZWUgb2JqZWN0IGFuZCByZXR1cm5zIGEgZGlzdGFuY2UgbWF0cml4IGJldHdlZW4gdGlwcy4gTmVlZCBvcmlnaW5hbCBjaXRhdGlvbi4KCmBgYHtyfQogICAgbGlicmFyeShwaHl0b29scykKICAKICAgIGxzKCJwYWNrYWdlOnBoeXRvb2xzIikKICMjIFBhaXJ3aXNlIGRpc3RhbmNlIGJldHdlZW4gdGlwcyAtIEZyb20gbGlicmFyeShhcGUpIGluIGxpYnJhcnkocGh5dG9vbHMpCiAgICBQYWlyd2lzZV9kaXN0IDwtIGNvcGhlbmV0aWModGhpc190cmVlKQoKYGBgCnlpZWxkcyBhIGRpc3RhbmNlIG1hdHJpeCAobGlzdCBvZiAyRCBtYXRyaWNlcykgb2YgYWxsIGRpc3RhbmNlcyBiZXR3ZWVuIHRheGEuCgoKYGBge3IsIGVjaG89RkFMU0V9CnN0cihQYWlyd2lzZV9kaXN0KQpgYGAKCiMjIyMgU3VtIG9mIGFsbCBwYWlyd2lzZSBkaXN0YW5jZXMgKCRGJCkKTm93IHdlIGNhbiB1c2UgYSBzZXQgb2Ygc3VtbWFyeSBzdGF0aXN0aWNzIHRvIGRlc2NyaWJlIHRob3NlIHBhaXJ3aXNlIGRpc3RhbmNlcy4gVGhlIHN1bSBvZiBhbGwgcGFpcndpc2UgZGlzdGFuY2VzLCAkRiQsIGlzIGZvcm1hbGx5IGNhbGxlZCAnRXh0ZW5zaXZlIHF1YWRyYXRpYyBlbnRyb3B5Jy4gKEl6c2FrIGFuZCBQYXBwICgyMDAwKSBhbmQgU3plaWRsICgyMDAyKSkuIEp1c3QgYXMgaXQgd2FzIHdpdGggYnJhbmNoIGxlbmd0aHMsIHRoaXMgaXMgYSByaWNobmVzcyBtZWFzdXJlIGFuZCwgYWNjb3JkaW5nbHksIHNob3VsZCBiZSB1c2VkIHRvIGFuc3dlciByaWNobmVzcyBxdWVzdGlvbnMuIAoKJCRGID0gXHN1bV97aX0gXHN1bV97an0gZF97aWp9JCQKYGBge3J9CiAgICAgICMgRiAtLSBFeHRlbnNpdmUgcXVhZHJhdGljIGVudHJvcHkKICAgICAgRl9xdWFkcmF0aWNfZW50cm9weV9pc19zdW1fb2ZfUEQgPC0gc3VtKFBhaXJ3aXNlX2Rpc3QpCmBgYAoKIyMjIyBNZWFuIHBhaXJ3aXNlIGRpc3RhbmNlIChNUEQpCk1lYW4gaW50ZXItc3BlY2llcyBkaXN0YW5jZXMuIFRoZSBtZWFuIG9mIGFsbCBwYWlyd2lzZSBkaXN0YW5jZXMsICRNUEQkIChhLmsuYS4gJEF2VEQkLCBhbmQgJFxEZWx0YV57K30kKSwgaXMgdGhlIG1lYW4gZGlzdGFuY2UgYmV0d2VlbiBzcGVjaWVzLiAoQ2xhcmtlIGFuZCBXYXJ3aWNrICgxOTk4KSwgV2ViYiBldCBhbC4gKDIwMDIsIDIwMDgpLCBLZW1iZWwgZXQgYWwuICgyMDEwKSkKJCRNUEQgPSBcZGZyYWN7XHN1bV97aWp9IGRfe2lqfX17UyhTLTEpfSQkCgpgYGB7cn0KICAgICAgIyBBbmNob3IgdGVzdCA9IE1QRCAobWVhbiBwYWlyd2lzZSBkaXN0YW5jZSkKCiAgICAgIE1lYW5fcGFpcndpc2VfZGlzdGFuY2UgPC0gUGFpcndpc2VfZGlzdCAvIChOdW1iZXJfb2ZfdGlwcyAqIChOdW1iZXJfb2ZfdGlwcyAtIDEpICkgCiAgICAgIApgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQpzdHIoTWVhbl9wYWlyd2lzZV9kaXN0YW5jZSkKYGBgCgojIyMjIE1QRCBhbmNob3JlZCB0byB0aGUgcm9vdCAKVGhlcmUgaXMgYW4gZXh0ZW50aW9uIHRvIG1lYW4gcGFpcndpc2UgZGlzdGFuY2UgY2FsY3VsYXRpb25zIGZyb20gSGVsbXVzIGV0IGFsLiAoMjAwNykgY2FsbGVkICRQU1YkLCAkUFNSJCwgYW5kICRQU0UkLCBwaHlsb2dlbmV0aWMgc3BlY2llcyB2YXJpYWJpbGl0eSwgcGh5bG9nZW5ldGljIHNwZWNpZXMgcmljaG5lc3MsIGFuZCBwaHlsb2dlbmV0aWMgc3BlY2llcyBldmVubmVzcy4gVGhlc2UgbWVhc3VyZXMgdGFrZSB0aGUgYmFzaWMgcGFpcndpc2UgZGlzdGFuY2UgY2FsY3VsYXRpb25zIGFuZCBhbmNob3IgdGhlbSB0byB0aGUgcm9vdCBvZiB0aGUgdHJlZSBzbyBkaXN0YW5jZXMgaGF2ZSBhIGNvbW1vbiBkZW5vbWluYXRvci4gVGhpcyBleHRlbnRpb24gaXMgaW1wbGVtZW50ZWQgYnkgdXNpbmcgdGhlIHNhbWUgZXF1YXRpb25zLCBqdXN0IHdpdGggYSBjb25zdHJhaW5lZCBzZXQgb2YgJGRfe2lqfSQgY29uZGl0aW9ucy4gU3BlY2lmaWNhbGx5LAoKCgoKJCRQU1YgPSBNUEQgPSBcZGZyYWN7XHN1bV97aWp9IGRfe2lqfX17UyhTLTEpfSQkCiQkUFNSID0gXHN1bV97aX0geyhcZGZyYWN7MX17Uy0xfSBcc3VtX3tqfSB7ZF97aWp9fSl9JCQKJCRQU0UgPSBcZGZyYWN7U317Uy0xfSBcc3VtX3tpan0gZF97aWp9cF97aX1wX3tqfSQkCgoKd2l0aCB0aGVzZSBzcGVjaWZpYyB2YWx1ZXMgb2YgJGRfe2lqfSQKCiQkZF97aml9PTAuNSooY197aWl9ICsgY197amp9IC0gY197aWp9KSBcXCAKXCBcXApvciBcXApcIFxcCmRfe2lqfSA9IDEgLSBjX3tpan0gLyAoXHNxcnR7Y197aWl9Y197amp9fSkgCiQkCmFuZAokJApjX3tpaX0gPSB0aGUgXCBzdW0gXCBvZiBcIGJyYW5jaCBcIGxlbmd0aHMgXCBmcm9tIFwgdGlwIFwgaSAgXCB0byBcIHRoZSBcIHJvb3QgXCBvZiBcIHRoZSBcIHBoeWxvZ2VuZXRpYyBcIHRyZWUuIFxcClwgXFwKY197aWp9ID0gdGhlIFwgc3VtIFwgIG9mIFwgYnJhbmNoIFwgbGVuZ3RocyBcIGZyb20gXCBmaXJzdCBcIGNvbW1vbiBcIGFuY2VzdG9yIFwgZm9yIFwgaSBcIGFuZCBcIGogXCB0byBcIHRoZSBcIHJvb3QuCiQkCgoKCiMjIyMgQXZlcmFnZSBkaXN0YW5jZSBiZXR3ZWVuIHR3byByYW5kb21seSBjaG9zZW4gc3BlY2llcwokSiQsIEludGVuc2l2ZSBxdWFkcmF0aWMgZW50cm9weSwgd2hpY2ggaXMgdGhlIGF2ZXJhZ2UgZGlzdGFuY2UgYmV0d2VlbiB0d28gcmFuZG9tbHkgY2hvc2VuIHNwZWNpZXMuIChJenNhayBhbmQgUGFwcCAyMDAwKQokJEogPSBcZGZyYWN7XHN1bV97aWp9ZF97aWp9fXtTXjJ9ICQkCgoKCgojIyMjIFNpbXBzb24ncyBkaXZlcnNpdHkgaW5kZXggZm9yIHBhaXJ3aXNlIGRpc3RhbmNlClRoZXJlIGhhcyBiZWVuIGEgbG9uZyBlZmZvcnQgdG8gcGVuIGEgcGh5bG9nZW5ldGljIGFuYWxvZ3kgdG8gYSBTaW1wc29uJ3MgZGl2ZXJzaXR5IGluZGV4LiAoc2VlIFJhbyAoMTk4MiksIENsYXJrZSBhbmQgV2Fyd2ljayAoMTk5OCksIFBhdm9pbmUgZXQgYWwuICgyMDA1KSwgSGFyZHkgYW5kIFNlbnRlcnJlICgyMDA3KSwgV2ViYiBldCBhbC4gKDIwMDIsIDIwMDgpLCBLZW1iZWwgZXQgYWwuICgyMDEwKSkuIFRoZSBjb25jbHVzaW9uIHNlZW1zIHRvIGJlIHRoYXQgdGhpcyBtZWFzdXJlIGlzIGVxdWl2aWxlbnQgdG8gc2NhbGluZyAkTVBEJCBieSBhYnVuZGFuY2UgJHBfe2l9JCBhbmQgJHBfe2p9JCB0byBnZXQgJE1QRF97QWJ9JC4gVGhpcyBpcyBhbHNvIGEgc3BlY2lhbCBjYXNlIG9mIFJhbydzIFF1YWRyYXRpYyBFbnRyb3B5LCAkUm9lJ3MgUUUkLiBOb3RlOiBub3QgdXNpbmcgYWJ1bmRhbmNlIG1lYXN1cmVzIHlldCBmb3IgRC1wbGFjZSBkYXRhLiAKCiQkTVBEX3tBYn0gPSBcc3VtX3tpfSBcc3VtX3tqfSBkX3tpan0gcF97aX0gcF97an0kJAoKCgoKIyMjIyBJbnRlcnNwZWNpZmljIGNvbXBhcmlzb25zIG9mIHBhaXJ3aXNlIGRpc3RhbmNlcwpUaGUgaW50ZXJzcGVjaWZpYyB2YXJpYW50IChyYXRoZXIgdGhhbiB0aGUgaW50cmFzcGVjaWZpYyBkZWZhdWx0IGRlc2NyaWJlZCBhYm92ZSkgZGVmaW5lcyB0aGUgZXhwZWN0ZWQgcGh5bG9nZW5ldGljIGRpc3RhbmNlIGJldHdlZW4gdHdvIGluZGl2ZGl1YWxzIHJhbmRvbWVseSBkcmF3biBjb25kaXRpb25hbGx5IG9uIHRoZSBmYWN0IHRoYXQgdGhleSBpbmRpdmR1bGFzIGZyb20gZGlmZmVyZW50IHNwZWNpZXMuIAokJEludGVyTVBEX3tBYn0gPSBcZGZyYWN7XHN1bV97aX0gXHN1bV97aiBcbmUgaX0gZF97aWp9IHBfe2l9IHBfe2p9IH17XHN1bV97aX0gXHN1bV97aiBcbmUgaX0gZF97aWp9IHBfe2l9IHBfe2p9fSAgJCQKCgoKIyMjIyBWYXJpYW5jZSBpbiBwYWlyd2lzZSBkaXN0YW5jZXMgKCRWUEQkKQpWYXJpYW5jZSBpbiBwYWlyd2lzZSBkaXN0YW5jZXMsICRWUEQkIChhLmsuYS4gJFZhclREJCBhbmQgJFxMYW1iZGFeKyQpLCBpcyBhIHJlZ3VsYXJpdHkgaW5kaWNlcy4gQ2xhcmtlIGFuZCBXYXJ3aWNrICgyMDAxKSBWYXJpYW5jZSBpcyByZWxhdGl2ZSB0byB0aXBzLCAkUyQsIG5vdCB0byB0b3RhbCBicmFuY2hlcyAoJEIkIGZyb20gYWJvdmUpLiBUaGVzZSBhcmUgdGhlIHJlc2lkdWFscywgdGhleSBjb21wYXJlIGVhY2ggaW5kaXZpZHVhbCBwYWlyd2lzZSBjb25uZWN0aW9uIHRvIHRoZSBvdmVyYWxsIG1lYW4uIAoKJCRWUEQgPSBcZGZyYWN7MX17UyhTLTEpfSAoXHN1bV97aX0gXHN1bV97aiBcbmUgaX0geyhkX3tpan0gLSBNUEQpXjJ9KSQkCgoKCgpgYGB7cn0KICAgICNQYWlyd2lzZSBkaXN0YW5jZS9hbGwgZGlzdGFuY2VzIC0tIFZhcmlhbmNlIG9mIHBhaXJ3aXNlIGRpc3RhbmNlcwoKICAgICAgIyBBbmNob3IgdGVzdCA9IFZQRCAodmFyaWF0aW9uIG9mIHBhaXJ3aXNlIGRpc3RhbmNlKSAjbmVlZCB0byBhZGp1c3QgdG8gZXF1YXRpb24gYWJvdmUuIAoKICAgICAgdmFyaWFuY2VfcGFpcndpc2VfZGlzdGFuY2UgPC0gdmFyKGFzLnZlY3RvcihQYWlyd2lzZV9kaXN0KSkKYGBgCgoKVmFyaWFudHMgb2YgJFZQRCQgYXJlICRWUERfe2FifSQgYW5kICRJbnRlclBWRF97QWJ9JCwgd2hlcmUgdmFyaWFuY2UgaXMgc2NhbGVkIGJ5IGFidW5kYW5jZSBvciBjb21wYXJlZCBpbiBhbmQgb3V0IG9mIHNwZWNpZXMuIFRoZXNlIGFyZSBhbHNvIHJlZ3VsYXJpdHkgaW5kaWNlcy4gCiQkClZQRF97QWJ9PSAKKFxzdW1fe2l9IFxzdW1fe2p9IG5fe2l9IG5fe2p9KSAqClxkZnJhY3tcc3VtX3tpfSBcc3VtX3tqfSBuX3tpfSBuX3tqfSAoZF97aWp9IC0gTVBEX3tBYn0pXjJ9CnsoXHN1bV97aX0gXHN1bV97an0gbl97aX0gbl97an0pXjIgLSBcc3VtX3tpfSBcc3VtX3tqfSAobl97aX0gbl97an0pXjJ9ClxcCm9yClxcCkludGVyVlBEX3tBYn0gPSAKKFxzdW1fe2l9IFxzdW1fe2ogXG5lIGl9IG5fe2l9IG5fe2p9KSAqClxkZnJhY3tcc3VtX3tpfSBcc3VtX3tqIFxuZSBpfSBuX3tpfSBuX3tqfSAoZF97aWp9IC0gSW50ZXJNUERfe0FifSleMn0Keyhcc3VtX3tpfSBcc3VtX3tqIFxuZSBpfSBuX3tpfSBuX3tqfSleMiAtIFxzdW1fe2l9IFxzdW1fe2ogXG5lIGl9IChuX3tpfSBuX3tqfSleMn0KJCQKCiMjIyBOZWFyZXN0IHBoeWxvZ2VuZXRpYyBuZWlnaGJvcgoKIyMjIyBEaXZlcmdlbmNlIGluZGljZXMKRGl2ZXJnZW5jZSBpbmRpY2VzIHVzaW5nIG5lYXJlc3QgZGlzdGFuY2U6ICRNTlREJCBhbmQgJE1OVERfe0FifSQsIE1lYW4gbmVhcmVzdCB0YXhvbiBkaXN0YW5jZSBhbmQgQWJ1bmRhbmNlLXdlaWdodGVkIE1OVEQuIChXZWJiIGV0IGFsLiAoMjAwMiwyMDA4KSwgS2VtYmVsIGV0IGFsLiAoMjAxMCkpLiAKCiRNTlREJCwgbWVhbiBuZWFyZXN0IHRheG9uIGRpc3RhbmNlLCBpcyB0aGUgbWVhbiBzaG9ydGVzdCBkaXN0YW5jZSBmcm9tIGEgc3BlY2llcyB0byBhbGwgb3RoZXIgaW4gdGhlIGFzc2VtYmxhZ2UuIFdlYmIgZXQgYWwgKDIwMDIsIDIwMDgpLCBLZW1iZWwgZXQgYWwuICgyMDEwKSAgCiQkCk1OVEQgPSAKXGRmcmFjezF9e1N9ClxzdW1fe2l9CmRfe2lfe21pbn19CiQkCgokTU5URF97QUJ9JCwgYWJ1bmRhbmNlIGFkanVzdGVkIG1lYW4gbmVhcmVzdCB0YXhvbiBkaXN0YW5jZS4gQWRqdXN0ZWQgYnkgc3BlY2llcyBwcm9wb3J0aW9ucyAoaS5lLiBzcGVjaWVzJyByZWxhdGl2ZSBhYnVuZGFuY2VzKSBXZWJiIGV0IGFsICgyMDAyLCAyMDA4KSwgS2VtYmVsIGV0IGFsLiAoMjAxMCkgICAKJCQKTU5URF97QWJ9ID0gClxzdW1fe2k9MX1ee1N9CltkX3tpX3ttaW59fSAqIHBfe2l9XQokJAoKIyMjIyBSZWd1bGFyaXR5IGluZGljZXMKUmVndWxhcml0eSBpbmRpY2VzIHVzaW5nIG5lYXJlc3QgZGlzdGFuY2VzOiAkVk5URCQsICRWTlREX3tBYn0kLCAkUEVfe2V2fSQuICAKCiRWTlREJCwgVmFyaWFuY2UgaW4gbmVhcmVzdCB0YXhvbiBkaXN0YW5jZXMsIGlzIHRoZSB2YXJpYW5jZSBpbiBuZWFyZXN0IHBhaXJ3aXNlIGRpc3RhbmNlLiBUdWNrZXIgZXQgYWwuICgyMDE2KQokJApWTlREID0gXGRmcmFjezF9e1N9ClxzdW1fe2ktMX1ee1N9ClsoZF97aV97bWlufX0gLSBNTlREKV4yXQokJAokVk5URF97QWJ9JCwgQWJ1bmRhbmNlIHdlaWdodGVkIHZhcmlhbmNlIGluIG5lYXJlc3QgdGF4b24gZGlzdGFuY2VzLCBpcyBzY2FsZXMgYnkgYWJ1bmRhbmNlIGluIHRoZSBzYW1lIHdheSBhcyBkZXNjcmllZCBhYm92ZS4gVHVja2VyIGV0IGFsLiAoMjAxNikKJCQKVk5URF97QWJ9ID0gXGRmcmFjCnsoXHN1bV97aX0gbl97aX0pIFxzdW1fe2l9IG5fe2l9IChkX3tpX3ttaW59fSAtIE1OVERfe0FifSleMn0Keyhcc3VtX3tpfSBuX3tpfSleMiAtIFxzdW1fe2l9IG5fe2l9IF4yfQokJAoKIyMjIyBQaHlsb2dlbmV0aWMgdmVyc2lvbiBvZiB0aGUgZnVudGlvbmFsICRGRV97dmV9JCBpbmRleAokUEVfdmUkLCBwaHlsb2dlbmV0aWMgZXZlbm5lc3MgaXMgYSBwaHlsb2dlbmV0aWMgdmVyc2lvbiBvZiB0aGUgZnVudGlvbmFsICRGRV97dmV9JCBpbmRleC4gRmlyc3QgYSBtaW5pbXUgc3Bhbm5pbiB0cmVlIChNU1QpIGlzIGNvbXB1dGVkIHVzaW5nIHRoZSBjb3BoZW5ldGljIGRpc3RhbmNlIG9idGFpbmVkIGZyb20gdGhlIHBoeWxvZ2VuZXRpYyB0cmVlLiBUaGUgTVNUIGNvbnRhaW5zIFMtMSBCcmFuY2hlcyBjb25uZWN0aW9uIHRoZSBTIHNwZWNpZXMuIFdlIGRlbm90ZSBsIGEgYnJhbmNoIG9uIHRoZSBNU1QsIGRpc3QoaSxqKSBpcyB0aGUgbGVuZ3RodGhlIGJyYW5jaCBsIHRoYXQgY29ubmVjdHMgc3BlY2llcyBpIGFuZCBqLiBuaSBpcywgYXMgZGVmaW5lZCBhYm91dmUsIHRoZSBhYnVuZGNlIG9mIHNwZWNpZXMgaSBpbiB0aGUgYXNzZWJsYWdlLiBWaWxsZWdlciBldCBhbC4gKDIwMDgpLCBEZWhsaW5nIGV0IGFsLiAoMjAxNCkuCgokJApXZWlnaHRlZCBcIGV2ZW5uZXNzOiBcXApFV197aX0gPSBcZGZyYWN7ZGlzdChpLGopfQp7KG5fe2l9ICsgbl97an0pLyhcc3VtX3trPTF9XntTfW5fe2t9KX0gXFwKXCBcXApQYXJ0aWFsIFwgd2VpZ2h0ZWQgXCBldmVubmVzczogXFwgClBFV197bH0gPSBcZGZyYWMKe0VXX3tsfX0Ke1xzdW1fe2w9MX1ee1MtMX0gRVdfe2x9fSBcXApcIFxcClBoeWxvZ2VuZXRpYyBcIGV2ZW5uZXNzOiBcXApQRV97dmV9ID0gXGRmcmFjCntcc3VtX3tsPTF9XntTLTF9IG1pbihQRVdfe2x9LCBcZGZyYWN7MX17Uy0xfSkgLSAoXGRmcmFjezF9e1MtMX0pfQp7MS0gKFxkZnJhY3sxfXtTLTF9KX0KJCQKCiMjIyBQaHlsb2dlbmV0aWMgaXNvbGF0aW9uCkEgcGh5bG9nZW5ldGljIGlzb2xhdGlvbiBpbmRleCByZXByZXNlbnRzIHRoZSByZWxhdGl2ZSBpc29sYXRpb24gb2YgYSBnaXZlbiBzcGVjaWVzIHdpdGhpbiBhIHBoeWxvZ2VuZXRpYyB0cmVlLiBTZXZlcmFsIGluZGljZXMgaGF2ZSBiZWVuIHByb3Bvc2VkIHNvIGZhciBidXQgd2UgZm9jdXMgaGVyZSBvbiB0aGUgZXZvbHV0aW9uYXJ5IGRpc3RpbmN0aXZlbmVzcyBpbmRleCBjYWxsZWQg4oCYRmFpciBQcm9wb3J0aW9u4oCZIGFzIHByb3Bvc2VkIGJ5IFJlZGRpbmcgKDIwMDMpIGFuZCBJc2FhYyAoMjAwNykuIAoKIyMjIyBFdm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzIChyaWNobmVzcyBpbmRpY2VzKQokRUQkLCBldm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzIGlzIGEgcmljaG5lc3MgaW5kaWNlcy4gTk9URTogbm90IGVxdWFsIHRvIEZhaXRoJ3MgUEQgYmVjYXVzZSB0aGUgJEVEX3tpfSQgYXJlIGNvbXB1dGVkIGZyb20gdGhlIHJlZ2lvbmFsIHBvb2wgb2Ygc3BlY2llcyBhbmQgc3VtZWQgYWNyb3NzIGEgZ2l2ZW4gYXNzZW1ibGFnZSAoaS5lLiBhIHN1YnNldCBvZiB0aGUgcmVnaW9uYWwgc3BlY2llcyBwb29sKS4gVHVja2VyICgyMDE2KSwgU2FmaSBldCBhbC4gKDIwMTMpLCBSZWRkaW5nICgyMDAzKSwgYW5kIElzYWFjICgyMDA3KQoKJCQKICBFRCA9IFxzdW1fe2l9RURfe2l9IFxcCiAgXCBcXCAKICB3aGVyZSBcIEVEX3tpfSA9IFxzdW1fe2IgXGluIEJfe3Rfe2l9fX0gXGRmcmFje0xfe2J9fXtTX3tifX0gCiQkCgokQUVEJCwgQWJ1bmRhbmNlLXdlaWdodGVkICRFRCQuIFR1Y2tlciAoMjAxNikgYW5kIENhZG90dGUgZXQgYWwuICgyMDEwKQokJApcc3VtX3tpfSBBRURfe2l9IFxcClwgXFwKd2hlcmUgXCBBRURfe2l9ID0gXHN1bV97YiBcaW4gQl97dF97aX19fSBcZGZyYWN7TF97Yn19e0Ffe2J9IH0qIHBfe2l9CiQkCgpgYGB7cn0KCiMgQnJ1bm8ncyBmdW5jdGlvbiBmb3IgRUQuIFByb3ZpZGVkIGluIGxpYnJhcnkoRkFSTSkKCmV2b2wuZGlzdGluY3QyIDwtIGZ1bmN0aW9uICh0cmVlLCB0eXBlID0gYygiZXF1YWwuc3BsaXRzIiwgImZhaXIucHJvcG9ydGlvbiIpLCAKICAgIHNjYWxlID0gRkFMU0UsIHVzZS5icmFuY2gubGVuZ3RocyA9IFRSVUUpIAp7CiAgICB0eXBlIDwtIG1hdGNoLmFyZyh0eXBlKQogICAgaWYgKGlzLnJvb3RlZCh0cmVlKSA9PSBGQUxTRSkgCiAgICAgICAgd2FybmluZygiQSByb290ZWQgcGh5bG9nZW55IGlzIHJlcXVpcmVkIGZvciBtZWFuaW5nZnVsIG91dHB1dCBvZiB0aGlzIGZ1bmN0aW9uIiwgCiAgICAgICAgICAgIGNhbGwuID0gRkFMU0UpCiAgICBpZiAoc2NhbGUgPT0gVFJVRSkgewogICAgICAgIGlmIChpcy51bHRyYW1ldHJpYyh0cmVlKSA9PSBUUlVFKSAKICAgICAgICAgICAgdHJlZSRlZGdlLmxlbmd0aCA8LSB0cmVlJGVkZ2UubGVuZ3RoLyhhcy5udW1lcmljKGJyYW5jaGluZy50aW1lcyh0cmVlKVsxXSkpCiAgICAgICAgZWxzZSB0cmVlJGVkZ2UubGVuZ3RoIDwtIHRyZWUkZWRnZS5sZW5ndGgvc3VtKHRyZWUkZWRnZS5sZW5ndGgpCiAgICB9CiAgICBpZiAodXNlLmJyYW5jaC5sZW5ndGhzID09IEZBTFNFKSAKICAgICAgICB0cmVlJGVkZ2UubGVuZ3RoIDwtIHJlcCgxLCBsZW5ndGgodHJlZSRlZGdlLmxlbmd0aCkpCiAgICBmb3IgKGkgaW4gMTpsZW5ndGgodHJlZSR0aXAubGFiZWwpKSB7CiAgICAgICAgc3BwIDwtIHRyZWUkdGlwLmxhYmVsW2ldCiAgICAgICAgbm9kZXMgPC0gLmdldC5ub2Rlcyh0cmVlLCBzcHApCiAgICAgICAgbm9kZXMgPC0gbm9kZXNbMToobGVuZ3RoKG5vZGVzKSAtIDEpXQogICAgICAgIGludGVybmFsLmJybGVuIDwtIHRyZWUkZWRnZS5sZW5ndGhbd2hpY2godHJlZSRlZGdlWywgCiAgICAgICAgICAgIDJdICVpbiUgbm9kZXMpXQogICAgICAgIGlmIChsZW5ndGgoaW50ZXJuYWwuYnJsZW4pICE9IDApIHsKICAgICAgICAgICAgaW50ZXJuYWwuYnJsZW4gPC0gaW50ZXJuYWwuYnJsZW4gKiBzd2l0Y2godHlwZSwgZXF1YWwuc3BsaXRzID0gc29ydChyZXAoMC41LCAKICAgICAgICAgICAgICAgIGxlbmd0aChpbnRlcm5hbC5icmxlbikpXmMoMTpsZW5ndGgoaW50ZXJuYWwuYnJsZW4pKSksIAogICAgICAgICAgICAgICAgZmFpci5wcm9wb3J0aW9uID0gewogICAgICAgICAgICAgICAgICBmb3IgKGogaW4gMTpsZW5ndGgobm9kZXMpKSB7CiAgICAgICAgICAgICAgICAgICAgc29ucyA8LSAubm9kZS5kZXNjKHRyZWUsIG5vZGVzW2pdKQogICAgICAgICAgICAgICAgICAgIG4uZGVzY2VuZGVudHMgPC0gbGVuZ3RoKHNvbnMkdGlwcykKICAgICAgICAgICAgICAgICAgICBpZiAoaiA9PSAxKSBwb3J0aW9uIDwtIG4uZGVzY2VuZGVudHMgZWxzZSBwb3J0aW9uIDwtIGMobi5kZXNjZW5kZW50cywgCiAgICAgICAgICAgICAgICAgICAgICBwb3J0aW9uKQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIDEvcG9ydGlvbgogICAgICAgICAgICAgICAgfSkKICAgICAgICB9CiAgICAgICAgRUQgPC0gc3VtKGludGVybmFsLmJybGVuLCB0cmVlJGVkZ2UubGVuZ3RoW3doaWNoLmVkZ2UodHJlZSwgCiAgICAgICAgICAgIHNwcCldKQogICAgICAgIGlmIChpID09IDEpIAogICAgICAgICAgICB3IDwtIEVECiAgICAgICAgZWxzZSB3IDwtIGModywgRUQpCiAgICB9CiAgICByZXR1cm4odykKfQoKYGBgCgpFdm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzIGlzIG91ciBiYXNpYyBtZWFzdXJlIG9mIHBoeWxvZ2VuZXRpYyBpc29sYXRpb24uICNUaGlzIHNob3VsZCBsaWtlbHkgYmUgJ2ZhaXIgcHJvcG9ydGlvbnMnIGluc3RlYWQgb2YgJ2VxdWFsLnNwbGl0cycuCmBgYHtyfQogICAgICBsaWJyYXJ5KHBoeXRvb2xzKQogICAgICBsaWJyYXJ5KEZBUk0pCiAgICAgICMgQ2FsY3VsYXRlIEVECiAgICAgICMgVXNpbmcgZXF1YWwuc3BsaXRzIG1ldGhvZCwgZmFzdGVyIGNvbXB1dGF0aW9uCiAgICAgIyBFdm9sdXRpb25hcnlfZGlzdGluY3RpdmVuZXNzX2kgPC0gZXZvbC5kaXN0aW5jdDIodGhpc190cmVlLCB0eXBlID0gImVxdWFsLnNwbGl0cyIpICAKICAgICAgCiAgICAgICMgRUQgLSBTdW1tZWQgZXZvbHV0aW9uYXJ5IGRpc3RpbmN0aXZlbmVzcwogICAgICMgRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzc19zdW0gPC0gc3VtKEV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3NfaSkKYGBgCgoKYGBge3J9CiNFdm9sdXRpb25hcnlfZGlzdGluY3RpdmVuZXNzX3N1bQpgYGAKCgoKV2UgY2FuIHJ1biBzb21lIHN0YW5kYXJkIHN1bW1hcnkgc3RhdGlzdGljcyAobWVhbiBhbmQgdmFyaWFuY2UpIG9uIHRoaXMgRUQgbWVhc3VyZS4gdmFyKEVkKSBzaG93cyB1cCBjbG9zZSB0byBWUEQgb24gdGhlIFBDQXMgaW4gdGhlIGludHJvLiBUdWNrZXIoMjAxNikKYGBge3J9CiAgICAgICMgbWVhbihFRCkKICAgICAjIG1lYW5fUGh5bG9nZW5ldGljX2lzb2xhdGlvbiA8LSBtZWFuKEV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3NfaSkKICAgICAgCiAgICAgICMgdmFyKEVEKQogICAgICAjdmFyaWFuY2VfUGh5bG9nZW5ldGljX2lzb2xhdGlvbiA8LSB2YXIoRXZvbHV0aW9uYXJ5X2Rpc3RpbmN0aXZlbmVzc19pKQpgYGAKCgoKYGBge3J9CiNtZWFuX1BoeWxvZ2VuZXRpY19pc29sYXRpb24KI3ZhcmlhbmNlX1BoeWxvZ2VuZXRpY19pc29sYXRpb24KYGBgCgojIyMjIE1lYW4gZXZvbHV0aW9uYXJ5IGRpc3RpbmN0aXZlbmVzcyAoZGl2ZXJnZW5jZSBpbmRpY2VzKQpUaGUgZGl2ZXJnZW5jZSBpbmRpY2VzIHZlcnNpb24gZm9yICRFRCQgaXMgbWVhbiBldm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzLCAkTUVEJC4gVGhlIG1lYW4gb2YgZXZvbHV0aW9uYXJ5IGRpc3RpbmN0aXZlbmVzcy4gUmVkZGluZyAoMjAwMykgYW5kIElzYWFjICgyMDA3KQokJApNRUQgPSBcZGZyYWMKe1xzdW1fe2l9IEVEX3tpfX0Ke1N9IFxcClwgXFwKd2l0aCBcXApcIFxcCkVEX3tpfSA9IFxzdW1fe2IgXGluIEJfe3Rfe2l9fX0gXGRmcmFje0xfe2J9fXtTX3tifX0KJCQKIyMjIyBFbnRyb3B5IG1lYXN1cmUgb2YgZXZvbHV0b25hcnkgZGlzdGluY3RpdmVuZXNzIChyZWd1bGFyaXR5IGluZGljZXMpClRoZSByZWd1bGFyaXR5IGluZGljZXMgZm9yICRFRCQvcGh5bG9nZW5ldGljIGlzb2xhdGlvbiBhcmUgJEhfe0VEfSQsICRFX3tFRH0kLCAkdmFyKEVEKSQsICRIX3tBRUR9JAoKJEhfe0VEfSQsIEVudHJvcHkgbWVhc3VyZSBvZiBldm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzLCBpcyB0aGUgc2hhbm5vbiBpbmRleCBhcHBsaWVkIHRvIGV2b2x1dGlvbmFyeSBkaXN0aW5jdGl2ZW5lc3MgdmFsdWVzLiBDYWRvdHRlIGV0IGFsLiAoMjAxMCkKJCQKSF97RUR9ID0gLVxzdW1fe2k9MX1ee1N9CigoXGRmcmFje0VEX3tpfX17XHN1bV97aT0xfV57U30gRURfe2l9fSkKKiBcbG4gKFxkZnJhY3tFRF97aX19e1xzdW1fe2k9MX1ee1N9IEVEX3tpfX0pKQokJAoKJEVfe0VEfSQsIEVxdWl0YWJpbGl0eSBvZiBldm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzLCBpcyAkSF97RUR9JCBjb250cm9sbGVkIGZvciBzcGVjaWVzIHJpY2huZXNzLiBDYWRvdHRlIGV0IGFsLiAoMjAxMCkKCiQkCkVfe0VEfSA9IFxkZnJhY3tIX3tFRH19e1xsbihTKX0KJCQKJHZhcihFRCkkLCBWYXJpYW5jZSBpbiBldm9sdXRpbm9hcnkgZGlzdGluY3RpdmVuZXNzLCBpcyB0aGUgdmFyaWFuY2Ugb2Ygc3BlY2llcyBldm9sdXRpb25hcnkgZGlzdGluY3RpdmVuZXNzLiBUdWNrZXIgKDIwMTYpCgokJAp2YXIoRUQpID0gXGRmcmFjezF9e1MtMX0gKgpcc3VtX3tpPTF9XntTfQooRURfe2l9LVxkZnJhY3tcc3VtX3tpPTF9XntTfSBFRF97aX19e1N9KV4yCiQkCiRIX3tFRF97QWJ9fSQsIEFidW5kYW5jZS13ZWlnaHRlZCB2ZXJzaW9uIG9mICRIX3tFRH0kLiBDYWRvdHRlIGV0IGFsLiAoMjAxNikKCiQkCkhfe0VEX3tBYn19ID0gLVxzdW1fe2k9MX1ee1N9CihcZGZyYWN7bl97aX1BRURfe2l9fXtcc3VtX3tpPTF9XntTfSBuX3tpfUFFRF97aX19ICoKXGxuKFxkZnJhY3tuX3tpfUFFRF97aX19e1xzdW1fe2k9MX1ee1N9IG5fe2l9QUVEX3tpfX0pKQokJAoKCiMjIEJldGEgZGl2ZXJzaXR5CkJldGEtZGl2ZXJzaXR5IGluZGljZXMKSS4gUmljaG5lc3MgaW5kaWNlcyAocHJlc2VuY2XigJNhYnNlbmNlIGRhdGEpCklJLiBEaXZlcmdlbmNlIGluZGljZXMgKHVzaW5nIHBhaXJ3aXNlIGRpc3RhbmNlcyBhbW9uZyBzcGVjaWVzKQoxLiBQcmVzZW5jZS9hYnNlbmNlIGRhdGEKQS4JRGVjb21wb3NpdGlvbiBpbnRvICwgLCAgZGl2ZXJzaXRpZXMKQi4JRGlyZWN0IGRpc3NpbWlsYXJpdGllcwoxLglVc2luZyBhbGwgZGlzdGFuY2VzCjIuCVVzaW5nIG5lYXJlc3QgZGlzdGFuY2VzCjIuIEFidW5kYW5jZSBkYXRhCkEuCURlY29tcG9zaXRpb24gaW50byAsICwgIGRpdmVyc2l0aWVzCkIuCURpcmVjdCBkaXNzaW1pbGFyaXRpZXMKSUlJLiBQYXJhbWV0cmljIGluZGljZXMKMS4gRXF1aXZhbGVudCBudW1iZXJzCjIuIEVudHJvcHkKCgojIyBUcmVlIHRvcG9sb2d5ClRyZWUgdG9wb2xvZ3kgaXMgYSBtZWFzdXJlIG9mIHRoZSBzaGFwZSBvZiB0aGUgb3ZlcmFsbCB0cmVlLiBUaGUgdHJlZSBjYW4gYmUgbG9wc2lkZWQgc2lkZS10by1zaWRlIG9yIGZyb250LXRvLWJhY2suIAoKT3VyIG1vc3QgdHJ1c3RlZCBpbmRleCBmb3IgdGhlIHRpcHB5IHZzIHRydW5reSBvZiBhIHRyZWUgaXMgdGhlIGdhbW1hIGluZGV4LCAkXGdhbW1hJC5UaGUgaW5kZXggY2hhcmFjdGVyaXplcyB0aGUgZGlzdHJpYnV0aW9uIG9mIGJyYW5jaGluZyBldmVudHMgd2l0aGluIHRoZSB0cmVlLiBUcmVlcyB3aXRoIM6zIDwgMCBoYXZlIHJlbGF0aXZlbHkgbG9uZ2VyIGJyYW5jaGVzIHRvd2FyZHMgdGhlIHRpcHMgb2YgdGhlIHBoeWxvZ2VueSAodGlwcHkgdHJlZXMpLCB3aGVyZWFzIHRyZWVzIHdpdGggzrMgPiAwIGhhdmUgcmVsYXRpdmVseSBsb25nZXIgaW50ZXItbm9kYWwgZGlzdGFuY2VzIHRvd2FyZHMgdGhlIHJvb3Qgb2YgdGhlIHBoeWxvZ2VueSAoc3RlbW15IHRyZWVzKS4gIHRrIHJlcHJlc2VudHMgYW4g4oCYZXZvbHV0aW9uYXJ5IHBlcmlvZOKAmSAobGltaXRzIGFyZSBnaXZlbiBieSB0d28gc3BlY2lhdGlvbiBldmVudHMpIG9yIGVxdWl2YWxlbnRseSBhbiBpbnRlcm5vZGUgZGlzdGFuY2UuIFB5YnVzIGFuZCBIYXJ2ZXkgKDIwMDApCgokJAogIFxnYW1tYSA9IFxkZnJhYwogIHsoXGRmcmFjezF9e1MtMn0qIFxzdW1fe2k9Mn1ee1MtMX0gKFxzdW1fe2s9Mn1ee2l9IEt0X3trfSkpLSBcZGZyYWN7MX17Mn0gKiBcc3VtX3tqPTJ9XntTfSBqdF97an19CiAgeyhcc3VtX3tqPTJ9XntTfSBqdF97an0pICogXHNxcnR7XGRmcmFjezF9ezEyKihTLTIpfX19CiQkCmBgYHtyfQogICAgICBsaWJyYXJ5KHBoeXRvb2xzKQogICAgICAKICAgICAgbHR0cyA8LSBsdHQodGhpc190cmVlLCBnYW1tYSA9IFRSVUUsIHBsb3QgPSBGQUxTRSkKYGBgCgpgYGB7cn0KbHR0cwpzdHIobHR0cykKYGBgCgpgYGB7cn0KICAgICAgbGluZWFnZXNfdGhyb3VnaF90aW1lIDwtIGFzLm51bWVyaWMobHR0c1tbMV1dKQogICAgICB0aW1lX3N0ZXBzIDwtIGFzLm51bWVyaWMobHR0c1tbMl1dKQogICAgICAjZXh0cmFjdCBHYW1tYSBpbmRleAogICAgICBnYW1tYSA8LSBsdHRzW1szXV0KICAgICAgZ2FtbWFfcF92YWx1ZSA8LSBsdHRzW1s0XV0KYGBgCgoKYGBge3J9CmxpbmVhZ2VzX3Rocm91Z2hfdGltZSAKdGltZV9zdGVwcyAKZ2FtbWEgCmdhbW1hX3BfdmFsdWUgCmBgYAoKClRoZXJlIGFyZSB0d28gb3RoZXIgcmVndWxhcmx5IHVzZWQgbWV0cmljcyB0aGF0IGluY2x1ZGUgYWJ1bmRhbmNlIG1lYXN1cmVzLiBOb3RlOiB3ZSBkb24ndCBoYXZlIGFidW5kYW5jZSBtZWFzdXJlcyBmb3IgRC1wbGFjZSBkYXRhLiAKCiRJQUMkLCBpbWJhbGFuY2Ugb2YgYWJ1bmRhbmNlIGF0IHRoZSBjbGFkZSBsZXZlbCwgcXVhbnRpZmllcyB0aGUgcmVsYXRpdmUgZGV2aWF0aW9uIGluIHRoZSBhYnVuZGFuY2UgZGlzdHJpYnV0aW9uIGZyb20gYSBudWxsIGNhc2Ugd2hlcmUgaW5kaXZpZHVhbHMgYXJlIGV2ZW5seSBwYXJ0aXRpb25lZCBiZXR3ZWVuIGNsYWRlIHNwbGl0cy4gJHYkIGlzIHRoZSBudW1iZXIgb2Ygbm9kZXMgaW4gdGhlIHBoeWxvZ2VuZXRpYyB0cmVlLiAgJG5fe2l9JCBpcywgYXMgZGVmaW5lZCBhYm92ZSwgdGhlIGFidW5kYW5jZSBvZiBzcGVjaWVzICRpJCBpbiB0aGUgYXNzZW1ibGFnZS4gICRcZXRhX3trfSQgaXMgdGhlIGV4cGVjdGVkIGFidW5kYW5jZSBzcGVjaWVzICRpJCB3b3VsZCBoYXZlIGlmIHRoZSBhYnVuZGFuY2Ugd2FzIHJhbmRvbWx5IHNwbGl0IGFtb25nIGxpbmVhZ2VzIGluIHRoZSBwaHlsb2dlbmV0aWMgdHJlZSBhdCBlYWNoIHNwZWNpYXRpb24gZXZlbnQuICBpcyB0aGUgbnVtYmVyIG9mIGxpbmVhZ2VzIG9yaWdpbmF0aW5nIGF0IG5vZGUgJGskIGluIHRoZSBzZXQgJHMoayxyb290KSQsIHdoaWNoIGNvbnRhaW5zIHRoZSBub2RlcyBsb2NhdGVkIG9uIHRoZSBwYXRoIGJldHdlZW4gbm9kZSAkayQgYW5kIHRoZSByb290IG9mIHRoZSBwaHlsb2dlbmV0aWMgdHJlZS4gTiBpcyB0aGUgdG90YWwgYXNzZW1ibGFnZSBhYnVuZGFuY2UuIENhZG90dGUgZXQgYWwuICgyMDEwKQoKJCQKXGRmcmFje1xzdW1fe2k9MX1ee1N9ICB8bl97aX0gLSBcaGF0e25fe2l9fXx9Cnt2fSBcXApcIFxcCndoZXJlIFxcIApcIFxcClxoYXR7bl97aX19ID0gXGRmcmFje059e1xwcm9kX3tLIFxpbiBzKGksIHJvb3QpfVxldGFfe2t9fQokJAoKJElfe2N9JCwgdGhlIENvbGxlc3MgaW5kZXgsIGlzIHRoZSBzdW0gb2YgdGhlIGFic29sdXRlIGRpZmZlcmVuY2VzIGluIHNwZWNpZXMgcmljaG5lc3MgYmV0d2VlbiBzaXN0ZXItY2xhZGVzIGF0IGVhY2ggaW50ZXJuYWwgbm9kZS4gRm9yIGZ1bGx5IHJlc29sdmVkIHRyZWVzLCBlYWNoIGludGVybmFsIG5vZGUgZGVmaW5lcyB0d28gc2lzdGVyLWNsYWRlcy4gJFNfezFrfSQgaXMgdGhlIG51bWJlciBvZiBzcGVjaWVzIGRlc2NlbmRpbmcgZnJvbSB0aGUgZmlyc3QgY2xhZGUgZGVmaW5lZCBieSBub2RlIGsgYW5kICRTX3sya30kIHRoYXQgb2YgdGhlIHNlY29uZCBjbGFkZS4gJHYkIGlzLCBhcyBkZWZpbmVkIGFib3ZlLCB0aGUgbnVtYmVyIG9mIG5vZGVzIGluIHRoZSBwaHlsb2dlbmV0aWMuIENvbGxlc3MgKDE5ODIpCgokJApJX3tjfSA9IFxzdW1fe2s9MX1ee3Z9IHxTX3sxa30gLSBTX3sya318CiQkCgoKCgojIyBNYWNyb2V2b2x1dGlvbmFyeSByYXRlcwoKYGBge3J9CgojZnVuY3Rpb24gbmFtZSA9IGJkLCBmdW5jdGlvbiBpbnB1dCA9IHRyZWUgb2YgdHlwZSAncGh5bG8nCnByaW50KGJkKSAKCmBgYAoKCgpgYGB7cn0KICMjIFNwZWNpYXRpb24gdnMgZXh0aW5jdGlvbiByYXRlcyBhbmQgTmV0IGRpdmVyc2lmaWNhdGlvbgogICAgIAoKICAgICAgYmRzIDwtIGJkKHRoaXNfdHJlZSkKICAgICAgc3BlY2lhdGlvbl9yYXRlIDwtIGJkc1sxXQogICAgICBleHRpbmN0aW9uX3JhdGUgPC0gYmRzWzJdCiAgICAgIGV4dGluY3Rpb25fcGVyX3NwZWNpYXRpb24gPC0gYmRzWzNdCiAgICAgIHNwZWNpYXRpb25fbWludXNfZXh0aW5jdGlvbiA8LSBiZHNbNF0KICAKYGBgCgoKYGBge3J9CgoKICAgICAgIyMgU3BlY2lhdGlvbiB2cyBleHRpbmN0aW9uIHJhdGVzIGFuZCBOZXQgZGl2ZXJzaWZpY2F0aW9uIGRlcGVuZGVudCBvbiB0cmFpdAogICAgICMgTi5mb3IuZG9tIDwtIHRhYmxlKHRoaXNfd29ybGRbLCA2XSkKICAjICAgIGlmKGxlbmd0aChOLmZvci5kb20pID09IDIpIHsKICAgICAgICBwYXIuZGl2LmRlcCA8LSBEaXZEZXAoIG15dHJlZSA9IHRoaXNfdHJlZSwgbXlXb3JsZCA9IHRoaXNfd29ybGQpCiAgICAgICAgdHJhaXRfMV9zcGVjaWF0aW9uIDwtIHBhci5kaXYuZGVwWzFdCiAgICAgICAgdHJhaXRfMl9zcGVjaWF0aW9uIDwtIHBhci5kaXYuZGVwWzJdCiAgICAgICAgdHJhaXRfMV9leHRpbmN0aW9uIDwtIHBhci5kaXYuZGVwWzNdCiAgICAgICAgdHJhaXRfMl9leHRpbmN0aW9uIDwtIHBhci5kaXYuZGVwWzRdCiAgICAgICAgdHJhbnNpdGlvbl9mcm9tX3RyYWl0XzFfdG9fMiA8LSBwYXIuZGl2LmRlcFs1XQogICAgICAgIHRyYW5zaXRpb25fZnJvbV90cmFpdF8yX3RvXzEgPC0gcGFyLmRpdi5kZXBbNl0KICAgICAgICB0cmFuc2l0aW9uX3JhdGVfcmF0aW9fMXRvMl9vdmVyXzJ0bzEgPC0gdHJhbnNpdGlvbl9mcm9tX3RyYWl0XzFfdG9fMi90cmFuc2l0aW9uX2Zyb21fdHJhaXRfMl90b18xCiAgICAgIApgYGAKCgoKCmBgYHtyfQpsaWJyYXJ5KFJPQ1IpCiAgICAgICAgIyMgQ3Jvd24gYWdlIHBlciB0cmFpdCBBVUMgYW5kIGVmZmVjdCBzaXplCiAgICAgICAgdGlwLmxlbmd0aCA8LSB0aGlzX3RyZWUkZWRnZS5sZW5ndGhbdGhpc190cmVlJGVkZ2VbLCAyXSAlaW4lIDE6TnRpcCh0aGlzX3RyZWUpXQogICAgICAgIHRpcC5sZW5ndGggPC0gKHRpcC5sZW5ndGggLSBtaW4odGlwLmxlbmd0aCkpIC8gKG1heCh0aXAubGVuZ3RoKSAtIG1pbih0aXAubGVuZ3RoKSkKICAgICAgICB0aGlzX3RyYWl0IDwtIHRoaXNfd29ybGRbbWF0Y2godGhpc190cmVlJHRpcC5sYWJlbCwgdGhpc193b3JsZFssIDhdKSwgNl0KICAgICAgICB0aXAubGVuZ3RoLjIgPC0gdGlwLmxlbmd0aFt0aGlzX3RyYWl0ID09IDJdCiAgICAgICAgdGlwLmxlbmd0aC4xIDwtIHRpcC5sZW5ndGhbdGhpc190cmFpdCA9PSAxXQogICAgICAgIG1vZGVsIDwtIGdsbShhcy5mYWN0b3IodGhpc190cmFpdCkgfiBsb2codGlwLmxlbmd0aCArIDEpLAogICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiKQogICAgICAgIGVmZmVjdC5zaXplIDwtIG1vZGVsJGNvZWZmaWNpZW50c1syXQogICAgICAgIyBwbG90KHkgPSB0aGlzX3RyYWl0IC0gMSwgeD0gbG9nKHRpcC5sZW5ndGgpKQogICAgICAgIHAgPC0gcHJlZGljdChtb2RlbCwgYXMuZmFjdG9yKHRoaXNfdHJhaXQpLCB0eXBlID0gInJlc3AiKQogICAgICAgIyBwb2ludHMoeSA9IHAsIHggPSBsb2codGlwLmxlbmd0aCksIGNvbCA9ICJyZWQiKQogICAgICAgIHByIDwtIHByZWRpY3Rpb24ocCwgYXMuZmFjdG9yKHRoaXNfdHJhaXQpKQogICAgICAgIGF1Yy5tb2RlbCA8LSBwZXJmb3JtYW5jZShwciwgbWVhc3VyZSA9ICJhdWMiKUB5LnZhbHVlc1tbMV1dCgogICAgICAKYGBgCgoKCmBgYHtyfQogICMjIFBoeWxvZ2VuZXRpYyBzaWduYWwgKEQpCiAgICAgICAgUGh5bG9nZW5ldGljX3NpZ25hbCA8LSBEc2lnKG15dHJlZSA9IHRoaXNfdHJlZSwgbXlXb3JsZCA9IHRoaXNfd29ybGQpCiAgICAgICAgCmBgYAoKCiMgU3BhdGlhbCBMb2NhdGlvbnMKCmBgYHtyfQoKbGlicmFyeShzcGRlcCkKICMjIFNwYXRpYWwgQW5hbHlzaXMKICAgICAgICBuYnMwIDwtIGtuZWFybmVpZ2goYXMubWF0cml4KHRoaXNfd29ybGRbLCAyOjNdKSwgayA9IDcsIGxvbmdsYXQgPSBUUlVFKQogICAgICAgIG5icyA8LSBrbm4ybmIobmJzMCwgc3ltID0gVFJVRSkgIyA3IHN5bW1ldHJpYyBuZWlnaGJvcnMKICAgICAgICBuYnMubGlzdHcgPC0gbmIybGlzdHcobmJzKQogICAgICAgIGZhY3RvcnMubmJzIDwtIGFzLmZhY3RvcihpZmVsc2UoaXMubmEodGhpc193b3JsZFssIDZdKSwgMywgdGhpc193b3JsZFssIDZdKSkKICAgICAgICBzcGF0aWFsLnRlc3RzIDwtIGpvaW5jb3VudC50ZXN0KGZ4ID0gZmFjdG9ycy5uYnMsIGxpc3R3ID0gbmJzLmxpc3R3KQogICAgICAgIHNwYXRpYWwudGVzdHMuZm9yYSA8LSBzcGF0aWFsLnRlc3RzW1sxXV0kc3RhdGlzdGljCiAgICAgICAgc3BhdGlhbC50ZXN0cy5kb20gPC0gc3BhdGlhbC50ZXN0c1tbMl1dJHN0YXRpc3RpYwogICAgICAgICNwcmV2YWxlbmNlIDwtIChOLmZvci5kb21bMV0gLSBOLmZvci5kb21bMl0pIC8gc3VtKE4uZm9yLmRvbSkKYGBgCgoKYGBge3J9CnJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMSA8LSBjYmluZCgKCiAgICAgICAgbnVtYmVyX29mX2JyYW5jaGVzLAogICAgICAgICNQeWxvX2RpdmVyc2l0eV9pc19zdW1fb2ZfQkwsCiAgICAgICAgI2F2ZXJhZ2VfcGh5bG9nZW5ldGljX2RpdmVyc2l0eV9pc19tZWFuX29mX0JMLAogICAgICAgICN2YXJpYW5jZV9QeWxvX2RpdmVyc2l0eV9pc192YXJpYW5jZV9vZl9CTCwKCiAgICAgICAgRl9xdWFkcmF0aWNfZW50cm9weV9pc19zdW1fb2ZfUEQsCiAgICAgICAgTWVhbl9wYWlyd2lzZV9kaXN0YW5jZSwKICAgICAgICB2YXJpYW5jZV9wYWlyd2lzZV9kaXN0YW5jZSwKCiAgICAgICAgI0V2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3Nfc3VtLAogICAgICAgICNtZWFuX1BoeWxvZ2VuZXRpY19pc29sYXRpb24sCiAgICAgICAgI3ZhcmlhbmNlX1BoeWxvZ2VuZXRpY19pc29sYXRpb24sCgogICAgICAgIGdhbW1hLAogICAgICAgIGdhbW1hX3BfdmFsdWUsCiAgICAgICAgc3BlY2lhdGlvbl9yYXRlLAogICAgICAgIGV4dGluY3Rpb25fcmF0ZSwKICAgICAgICBleHRpbmN0aW9uX3Blcl9zcGVjaWF0aW9uLAogICAgICAgIHNwZWNpYXRpb25fbWludXNfZXh0aW5jdGlvbiwKICAgICAgICB0cmFpdF8xX3NwZWNpYXRpb24sCiAgICAgICAgdHJhaXRfMl9zcGVjaWF0aW9uICwKICAgICAgICB0cmFpdF8xX2V4dGluY3Rpb24gLAogICAgICAgIHRyYWl0XzJfZXh0aW5jdGlvbiAsCiAgICAgICAgdHJhbnNpdGlvbl9mcm9tX3RyYWl0XzFfdG9fMiAsCiAgICAgICAgdHJhbnNpdGlvbl9mcm9tX3RyYWl0XzJfdG9fMSAsCiAgICAgICAgdHJhbnNpdGlvbl9yYXRlX3JhdGlvXzF0bzJfb3Zlcl8ydG8xICwKICAgICAgICBQaHlsb2dlbmV0aWNfc2lnbmFsLAogICAgICAgIHNwYXRpYWwudGVzdHMuZm9yYSwKICAgICAgICBzcGF0aWFsLnRlc3RzLmRvbSwKICAgICAgICMgcHJldmFsZW5jZSwKICAgICAgICMgYXVjLm1vZGVsLAogICAgICAgIGVmZmVjdC5zaXplCiAgICAgICkKICAgICAgI3Jvd25hbWVzKHJlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMSkgPC0gMQoKICAgICAgI3Jlc3VsdHNfc3VtbWFyeV9tYXRyaXhfMiA8LSBjYmluZCgKICAgICAgIyAgYyhFdm9sdXRpb25hcnlfZGlzdGluY3RpdmVuZXNzLE5BKSwKICAgICAgIyAgbGluZWFnZXNfdGhyb3VnaF90aW1lLAogICAgICAjICB0aW1lX3N0ZXBzCiAgICAgICMpCiAgICAgICNjb2xuYW1lcyhyZXN1bHRzX3N1bW1hcnlfbWF0cml4XzIpIDwtIGMoIkV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3MiLCAibGluZWFnZXNfdGhyb3VnaF90aW1lIiwgInRpbWVfc3RlcHMiKQogICAgICAjaGVhZChyZXN1bHRzX3N1bW1hcnlfbWF0cml4XzIpCgogICAgICAjIyMgUmV0dXJucyBmcm9tIGZ1bmN0aW9uIGluIGxpc3QgZm9ybQogICAgICAjcmV0dXJucyA8LSBsaXN0KAogICAgICAgICNCcmFuY2hfTGVuZ3RocywKICAgICAgICAjUGFpcndpc2VfZGlzdCwKICAgICAgIyAgcmVzdWx0c19zdW1tYXJ5X21hdHJpeF8xLAogICAgICAjICByZXN1bHRzX3N1bW1hcnlfbWF0cml4XzIKCiAgICAgICMpCgogICAgICAjbmFtZXMocmV0dXJucykgPC0gYygKICAgICAgICAjIkJyYW5jaF9MZW5ndGhzIiwKICAgICAgICAjIlBhaXJ3aXNlX2Rpc3RhbmNlIiwKICAgICAgICMgInJlc3VsdHNfc3VtbWFyeV9vZl9zaW5nbGVfdmFsdWVfb3V0cHV0cyIsCiAgICAgICAjICJyZXN1bHRzX3N1bW1hcnlfbWF0cml4X29mX211bHRpX3ZhbHVlX291dHB1dHMiCiAgICAgICMpCiAgICAgIAogICAgICAKYGBgCgoKCiMjIE1vZHVsZTIoKSByZXR1cm5zIHRoZXNlIHR3byBtYXRyaWNlcyBhcyBhIGxpc3QgCgoKCmBgYHtyLCBlY2hvPUZBTFNFfQoja2FibGUocmV0dXJucyRyZXN1bHRzX3N1bW1hcnlfb2Zfc2luZ2xlX3ZhbHVlX291dHB1dHMsIGNhcHRpb249ICJUaGlzIGlzIG91ciB3b3JsZCIpCiAgICAgCmBgYAoKCmBgYHtyLCBlY2hvPUZBTFNFfQogI2thYmxlKHJldHVybnMkcmVzdWx0c19zdW1tYXJ5X21hdHJpeF9vZl9tdWx0aV92YWx1ZV9vdXRwdXRzLCBjYXB0aW9uPSAiVGhpcyBpcyBvdXIgd29ybGQiKQpgYGAKCgoKCjwhLS1jaGFwdGVyOmVuZDpUcmVlX2FuZF9zcGFjZV9hbmFseXNpc19ub3RlYm9va18yLlJtZC0tPgoKLS0tCnRpdGxlOiAnRC1wbGFjZSBGQVJNIGRvY3VtZW50YXRpb246IFJ1bm5pbmcgc2ltdWxhdGlvbnMgb24gdGhlIGNsdXN0ZXInCmF1dGhvcjogIlR5IFR1ZmYsIEJydW5vIFZpbGVsYSwgYW5kIENhcmxvcyBCb3Rlcm8iCmRhdGU6ICdwcm9qZWN0IGJlZ2FuOiAxNSBNYXkgMjAxNiwgZG9jdW1lbnQgdXBkYXRlZDogYHIgc3RyZnRpbWUoU3lzLnRpbWUoKSwgCmZvcm1hdCAgPSAiJWQgJUIgJVkiKWAnCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKYmlibGlvZ3JhcGh5OiBGQVJNIHBhY2thZ2UuYmliCi0tLQoKUnVubmluZyBhbiBSIHNjcmlwdCBvbiB0aGUgY2x1c3RlciByZXF1aXJlcyB0d28gcGFydHM6IGFuIFIgc2NyaXB0IHdpdGggdGhlIGNvZGUKdG8gYmUgcnVuIGFuZCBhIFBCUyBzY3JpcHQgdG8gY29udHJvbCBob3cgdGhhdCBSIHNjcmlwdCBpcyBydW4gb24gdGhlIGNsdXN0ZXIuCgoKVGhlcmUgYXJlIHR3byBkaWZmZXJlbnQgY2x1c3RlcnMgYXQgV3VzdGwuZWR1LCBhbiBvbGQgYW5kIGEgbmV3IGNsdXN0ZXIuIFRoaXMKc2NyaXB0IHJ1bnMgdGhlIFIgY29kZSBvbiB0aGUgbmV3IGNsdXN0ZXIuIAoKCmBgYHtiYXNofQojIS9iaW4vYmFzaAojUEJTIC1OIEZvdXJfbW9kZWxfcnVuIAojUEJTIC1WIAkJCQkJCiNQQlMgLWwgd2FsbHRpbWU9MjM6NTk6MDAJCQkJCiNQQlMgLWwgcG1lbT0xMjAwbWIgCiNQQlMgLWwgbm9kZXM9MTpwcG49MTpoYXN3ZWxsIAojUEJTIC10IDEtMTAwMAoKCmVjaG8gJFBCU19BUlJBWUlECgpjZCAvaG9tZS9jYm90ZXJvL215ZGlyZWN0b3J5L0ZvdXJfbW9kZWxfY29tcGFyZQptb2R1bGUgbG9hZCBSCgpleHBvcnQgUl9MSUJTPSRIT01FL3JsaWJzCiNSIENNRCBJTlNUQUxMIC0tbGlicmFyeT0vaG9tZS90dHVmZi9ybGlicyAgRkFSTV8xLjAudGFyLmd6CgpSc2NyaXB0IC0tdmFuaWxsYSAuL0ZBUk1fZm91cl9tb2RlbF9jb21wYXJlLlIgJHtQQlNfQVJSQVlJRH0KYGBgCgoKV2Ugd2VyZSByZWd1bGFybHkgY2F1c2luZyBwcm9ibGVtcyBydW5uaW5nIHRvIG1hbnkgam9icyBvbiB0aGUgbmV3IGNsdXN0ZXIgYW5kIAp3ZSB3ZXJlIGFza2VkIHRvIG1vdmUgdG8gdGhlIG9sZCBjbHVzdGVyLiBUaGlzIGNsdXN0ZXIgaGFzIHNsb3dlciBpbmRpdmlkdWFsIApwcm9jZXNzb3JzLCBidXQgd2UgY2FuIHJ1biBtb3JlIGpvYnMgYXQgb25lIHRpbWUsIHNvIHByb2R1Y3Rpdml0eSBoYXMgc3RheWVkIAphYm91dCB0aGUgc2FtZS4gCgpgYGB7YmFzaH0KIyEvYmluL2Jhc2gKI1BCUyAtTiBGQVJNX3RoaXJkX3J1bl9vbGQgCiNQQlMgLVYgCQkJCQkKI1BCUyAtbCB3YWxsdGltZT0xNjA6MDA6MDAJCQkJCiNQQlMgLWwgcG1lbT0xMjAwbWIgCiNQQlMgLXEgb2xkCiNQQlMgLWwgbm9kZXM9MTpwcG49MTpuZWhhbGVtIAojUEJTIC10IDEtNTAwCgoKZWNobyAkUEJTX0FSUkFZSUQKCmNkIC9ob21lL3R0dWZmL215ZGlyZWN0b3J5L0ZvdXJfbW9kZWxfY29tcGFyZQptb2R1bGUgbG9hZCBSCgpleHBvcnQgUl9MSUJTPSRIT01FL3JsaWJzCiNSIENNRCBJTlNUQUxMIC0tbGlicmFyeT0vaG9tZS90dHVmZi9ybGlicyAgRkFSTV8xLjAudGFyLmd6CgpSc2NyaXB0IC0tdmFuaWxsYSAuL0ZBUk1fZm91cl9tb2RlbF9jb21wYXJlLlIgJHtQQlNfQVJSQVlJRH0gCgpgYGAKCgpUaGUgZmluYWwgYXJndW1lbnQgaW4gdGhlICNQQlMgc2NyaXB0IGFib3ZlICgjUEJTIC10IDEtNTAwKSBjb250cm9scyB0aGUgc2VyaWFsIApydW5uaW5nIHNjaGVtYSBmb3IgcnVubmluZyBtYW55IHNpbXVsdGFuaW91cyBpbnN0YW5jZXMgb2YgdGhlIFIgc2NyaXB0IGF0IGEgCnRpbWUuIFRoaXMgYXJndW1lbnQgaXMgcGFzc2VzIHRvIFIgYXMgYW4gaW50ZWdlciB2YWx1ZSB1c2luZyB0aGUgZm9sbG93aW5nCmFyZ3VlbWVudHMgaW5zaWRlIFIuIApgYGB7cn0KCmFyZ3MgPC0gY29tbWFuZEFyZ3ModHJhaWxpbmdPbmx5ID0gRkFMU0UpICM3IGVsZW1lbnRzIGFyZSBwYXNzZWQgZnJvbSB0aGUgUEJTCgpOQUkgPC0gYXMubnVtZXJpYyhhcmdzWzddKSAjIHRoZSBzZXZlbnRoIG9mIHRob3NlIGVsZW1lbnRzIGlzIHRoZSBhcnJheSBpbnRlZ2VyLgoKYGBgCgoKSGVyZSBpcyBhIHdvcmtpbmcgZXhhbXBsZSBvZiBob3cgdG8gc2V0IHVwIHRoZSBSIHNjcmlwdC4KYGBge3J9CiNpbnN0YWxsLnBhY2thZ2VzKCJyZm9hYXMiKQpsaWJyYXJ5KHJmb2FhcykKCiMjSWYgdGhlIFBCUyBzY3JpcHQgc3RhcnRlZCB0aGlzIGNvZGUgcnVubmluZyBhbmQgcGFzc2VkIHRoZSBudW1iZXIgMTMKIyN0byB0aGlzIHBhcnRpY3VsYXIgcnVuIG9mIGEgbGFyZ2VyIHNlcmlhbCBzZXQuIAoKCiNhcmdzIDwtIGNvbW1hbmRBcmdzKHRyYWlsaW5nT25seSA9IEZBTFNFKSAKCk5BSSA8LSAxMyAjYXMubnVtZXJpYyhhcmdzWzddKQoKCXNheUhlbGxvIDwtIGZ1bmN0aW9uKGxvb3BfbnVtYmVyKXsKICAgCSAgcHJpbnQocGFzdGUwKCJJIGNhbiBjb3VudCB0byAiLCBsb29wX251bWJlciwgIiEgICAiLCBjb29sKGZyb209IlR5IikpKQoJfQoKCXNheUhlbGxvKE5BSSkKCmBgYAoKCllvdSBsb2dvbiB0byB0aGUgY2x1c3RlciB1c2luZyBsaW51eC91bml4IGNvZGUgZnJvbSB0aGUgY29tbWFuZCBsaW5lIAp0ZXJtaW5hbCBvbiB5b3UgY29tcHV0ZXIuIE9wZW4gdGhlIHRlcm1pbmFsIGFuZCBwdXQgaW4geW91IGxvZ2luIGluZm8uCgoKYGBge2Jhc2h9CnNzaCAtWSB0dHVmZkBsb2dpbi5jaHBjLnd1c3RsLmVkdQpwYXNzd29yZDpfX19fX19fCmBgYAoKVXBvbiBmaXJzdCBsb2dpbiwgeW91IHdpbGwgYmUgaW4gYSBmb2xkZXIgY2FsbGVkICdIT01FJyB3aXRoIGEgc2VyaWVzIG9mIHN5c3RlbSAKZmlsZXMgaW4gaXQuIFlvdSB3aWxsIHdhbnQgdG8gdXNlIGFuIEZUUCBjbGllbnQgdG8gdmlldyBhbmQgb3JnYW5pemUgdGhlc2UgCmZpbGVzLiBJIHByZWZlciBGaWxlemlsbGEsIGJ1dCB0aGVyZSBhcmUgc2V2ZXJhbCBvdGhlciBnb29kIGNsaWVudHMgYXZhaWxhYmxlIApmb3IgZnJlZS4gRG93bmxvYWQgZmlsZXppbGxhLCBtYWtlIHN1cmUgaXQncyBpbiB5b3VyIGFwcGxpY2F0aW9ucyBmb2xkZXIsIGFuZApvcGVuIGl0LiBZb3Ugc2hvdWxkIHNlZSBhIHdpbmRvdyB0aGF0IGxvb2tzIGxpa2UgYSBuZXdlciB2ZXJzaW9uIG9mIHRoaXMuIFRoZSAKbGVmdCBwYW5lbHMgYXJlIHRoZSBmaWxlcyBvbiB0aGUgY29tcHV0ZXIgeW91J3JlIHdvcmtpbmcgZnJvbSBhbmQgdGhlIHJpZ2h0CnR3byBwYW5lbHMgd2lsbCBzaG93IHRoZSBmaWxlcyBvbiB0aGUgc2VydmVyIG9uY2UgeW91IGxvZyBpbiB0aHJvdWdoIEZpbGV6aWxsYQphbHNvLiAKCiFbQSBmcmVzaCBGaWxlemlsbGEgd2luZG93XShGaWxlemlsbGEucG5nKQoKIVtTdGFydCBhIG5ldyBzZXJ2ZXIgbGlua10oc2l0ZSBtYW5hZ2VyLnBuZykKCgoKCiFbU3RhcnQgYSBuZXcgc2l0ZSBhbmQgbmFtZSB0aGF0IG5ldyBzaXRlXShOZXcgc2l0ZSBuYW1lLnBuZykKCgohW1NlbGVjdCBhIHNlY3VyZSBzc2ggZmlsZSB0cmFuc2ZlciBwcm90b2NvbF0oU0ZUUC5wbmcpCgoKIVtMb2dpbiBhcyBub3JtYWxdKENob29zZSBub3JtYWwucG5nKQoKCiFbRW50ZXIgcGFzc3dvcmRdKEVudGVyIHBhc3N3b3JkLnBuZykKCgohW1lvdSBuZWVkIHRvIGNyZWF0ZSB0d28gbmV3IGRpcmVjdG9yaWVzIChmb2xkZXJzKSBmb3IgdXMgdG8gd29yayBvdXQgb2YuIENhbGwgb25lICdybGlicycgYW5kIHRoZSBvdGhlciAnbXlkaXJlY3RvcnknXShDcmVhdGUgdHdvIGZpbGVzIHdpdGhpbiB5b3VyIGhvbWUgZmlsZS5wbmcpCgoKIVtXaXRoaW4gbXlkaXJlY3RvcnksIGNyZWF0ZSBhbm90aGVyIGZvbGRlciBjYWxsZWQgJ0ZvdXJfbW9kZWxfY29tcGFyZSddKENyZWF0ZSBGb3VyX21vZGVsc19jb21wYXJlIGZvbGRlci5wbmcpCgohW1dpdGhpbiAnRm91cl9tb2RlbF9jb21wYXJlJywgY3JlYXRlIHR3byBmb2xkZXJzIGNhbGxlZCAnTW9kdWxlXzFfb3V0cHV0cycgYW5kICdNb2R1bGVfMl9vdXRwdXRzJy4gVGhlbiBkcmFnIHRocmVlIGZpbGVzIGZyb20geW91ciBjb21wdXRlciBmaWxlcyBvbiB0aGUgbGVmdCB0byB0aGUgc2VydmVyIGZvbGRlcnMgb24gdGhlIHJpZ2h0OiBvbmUgLlIgZmlsZSwgb25lIC5wYnMgZmlsZSwgYW5kIGEgemlwIGZpbGUgd2l0aCB0aGUgcGFja2FnZSBGQVJNIGluIGl0LiBUaGVzZSBzaG91bGQgYmUgbmFtZWQgRkFSTV9mb3VyX21vZGVsX2NvbXBhcmUuUiwgRkFSTV9mb3VyX21vZGVsX2NvbXBhcmVfb2xkX2NsdXN0ZXIucGJzLCBhbmQgRkFSTV8xLjAudGFyLmd6IC5dKENyZWF0ZSBtb2R1bGUgZm9sZGVycy5wbmcpCgoKCgpPbmNlIGxvZ2dlZCBpbiwgeW91IG5lZWQgdG8gY2hhbmdlIHRoZSBkaXJlY3RvcnkKYGBge2Jhc2h9CmNkIC9ob21lL3R0dWZmL215ZGlyZWN0b3J5L0ZvdXJfbW9kZWxfY29tcGFyZQpgYGAKCgoKCgoKCgoKCgoKCiFbXShGaWxlcyBmcm9tIG1vZHVsZSAxLnBuZykKCiFbXShGaWxlcyBmcm9tIG1vZHVsZSAyLnBuZykKCgoKCgoKCgoKCgoKCgoKCgo8IS0tY2hhcHRlcjplbmQ6VXNpbmdfdGhlX2NsdXN0ZXJfbWFya2Rvd24uUm1kLS0+Cgo=